home *** CD-ROM | disk | FTP | other *** search
/ PC Open 107 / PC Open 107 CD 1.bin / CD1 / INTERNET / COPIA SITI / HTTrack / httrack.exe / {app} / src / htscore.c < prev    next >
Encoding:
C/C++ Source or Header  |  2005-02-05  |  113.2 KB  |  3,644 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Main source                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. #ifndef  _WIN32_WCE
  41. #include <fcntl.h>
  42. #endif
  43. #include <ctype.h>
  44.  
  45. /* File defs */
  46. #include "htscore.h"
  47.  
  48. /* specific definitions */
  49. #include "htsbase.h"
  50. #include "htsnet.h"
  51. #include "htsbauth.h"
  52. #include "htsmd5.h"
  53. #include "htsindex.h"
  54.  
  55. /* external modules */
  56. #include "htsmodules.h"
  57.  
  58. // htswrap_add
  59. #include "htswrap.h"
  60.  
  61. // parser
  62. #include "htsparse.h"
  63.  
  64. /* Cache */
  65. #include "htszlib.h"
  66.  
  67.  
  68. /* END specific definitions */
  69.  
  70.  
  71. /* HTML parsing */
  72. #if HTS_ANALYSTE
  73.  
  74. t_hts_htmlcheck_init    hts_htmlcheck_init = NULL;
  75. t_hts_htmlcheck_uninit  hts_htmlcheck_uninit = NULL;
  76. t_hts_htmlcheck_start   hts_htmlcheck_start = NULL;
  77. t_hts_htmlcheck_end     hts_htmlcheck_end = NULL;
  78. t_hts_htmlcheck_chopt   hts_htmlcheck_chopt = NULL;
  79. t_hts_htmlcheck_process hts_htmlcheck_preprocess = NULL;
  80. t_hts_htmlcheck_process hts_htmlcheck_postprocess = NULL;
  81. t_hts_htmlcheck         hts_htmlcheck = NULL;
  82. t_hts_htmlcheck_query   hts_htmlcheck_query = NULL;
  83. t_hts_htmlcheck_query2  hts_htmlcheck_query2 = NULL;
  84. t_hts_htmlcheck_query3  hts_htmlcheck_query3 = NULL;
  85. t_hts_htmlcheck_loop    hts_htmlcheck_loop = NULL;
  86. t_hts_htmlcheck_check   hts_htmlcheck_check = NULL;
  87. t_hts_htmlcheck_pause   hts_htmlcheck_pause = NULL;
  88. t_hts_htmlcheck_filesave       hts_htmlcheck_filesave = NULL;
  89. t_hts_htmlcheck_linkdetected   hts_htmlcheck_linkdetected = NULL;
  90. t_hts_htmlcheck_linkdetected2  hts_htmlcheck_linkdetected2 = NULL;
  91. t_hts_htmlcheck_xfrstatus hts_htmlcheck_xfrstatus = NULL;
  92. t_hts_htmlcheck_savename  hts_htmlcheck_savename = NULL;
  93. t_hts_htmlcheck_sendhead  hts_htmlcheck_sendhead = NULL;
  94. t_hts_htmlcheck_receivehead  hts_htmlcheck_receivehead = NULL;
  95.  
  96. extern void set_wrappers(void);
  97.  
  98. char _hts_errmsg[1100]="";
  99. int _hts_in_html_parsing=0;
  100. int _hts_in_html_done=0;  // % done
  101. int _hts_in_html_poll=0;  // parsing
  102. int _hts_setpause=0;
  103. //httrackp* _hts_setopt=NULL;
  104. char** _hts_addurl=NULL;
  105.  
  106. /* external modules */
  107. extern int hts_parse_externals(htsmoduleStruct* str);
  108. extern void htspe_init(void);
  109.  
  110. //
  111. int _hts_cancel=0;
  112. #endif
  113.  
  114.  
  115.  
  116. int exit_xh;          /* quick exit (fatal error or interrupt) */
  117.  
  118. /* debug */
  119. #if DEBUG_SHOWTYPES
  120. char REG[32768]="\n";
  121. #endif
  122. #if NSDEBUG
  123. int nsocDEBUG=0;
  124. #endif
  125.  
  126. //
  127. #define _CLRSCR printf("\33[m\33[2J");
  128. #define _GOTOXY(X,Y) printf("\33[" X ";" Y "f");
  129.  
  130. #if DEBUG_CHECKINT
  131.  #define _CHECKINT_FAIL(a) printf("\n%s\n",a); fflush(stdout); exit(1);
  132.  #define _CHECKINT(obj_ptr,message) \
  133.    if (obj_ptr) {\
  134.      if (( * ((char*) (obj_ptr)) != 0) || ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0)) {\
  135.        char msg[1100];\
  136.        if (( * ((char*) (obj_ptr)) != 0) && ( * ((char*) (((char*) (obj_ptr)) + sizeof(*(obj_ptr))-1)) != 0))\
  137.          sprintf(msg,"* PANIC: Integrity error (structure crushed)  in: %s",message);\
  138.        else if ( * ((char*) (obj_ptr)) != 0)\
  139.          sprintf(msg,"* PANIC: Integrity error (start of structure) in: %s",message);\
  140.        else\
  141.          sprintf(msg,"* PANIC: Integrity error (end of structure)   in: %s",message);\
  142.        _CHECKINT_FAIL(msg);\
  143.      }\
  144.    } else {\
  145.      char msg[1100];\
  146.      sprintf(msg,"* PANIC: NULL pointer in: %s",message);\
  147.      _CHECKINT_FAIL(msg);\
  148.    }
  149. #endif
  150.  
  151. #if DEBUG_HASH
  152.   // longest hash chain?
  153.   int longest_hash[3]={0,0,0},hashnumber=0;
  154. #endif
  155.  
  156. // demande d'interaction avec le shell
  157. #if HTS_ANALYSTE
  158. char HTbuff[2048];
  159. #endif
  160.  
  161.  
  162.  
  163. // DΘbut de httpmirror, routines annexes
  164.  
  165. // version 1 pour httpmirror
  166. // flusher si on doit lire peu α peu le fichier
  167. #define test_flush if (opt.flush) { fflush(opt.log); fflush(opt.errlog); }
  168.  
  169. // pour allΘger la syntaxe, des raccourcis sont crΘΘs
  170. #define urladr   (liens[ptr]->adr)
  171. #define urlfil   (liens[ptr]->fil)
  172. #define savename (liens[ptr]->sav)
  173. //#define level    (liens[ptr]->depth)
  174.  
  175. // au cas o∙ nous devons quitter rapidement xhttpmirror (plus de mΘmoire, etc)
  176. // note: partir de liens_max.. vers 0.. sinon erreur de violation de mΘmoire: les liens suivants
  177. // ne sont plus α nous.. agh! [dur celui-lα]
  178. #if HTS_ANALYSTE
  179. #define HTMLCHECK_UNINIT { \
  180. if ( (opt.debug>0) && (opt.log!=NULL) ) { \
  181. fspc(opt.log,"info"); fprintf(opt.log,"engine: end"LF); \
  182. } \
  183. hts_htmlcheck_end(); \
  184. }
  185. #else
  186.  #define HTMLCHECK_UNINIT 
  187. #endif
  188.  
  189. #define XH_extuninit do { \
  190.   int i; \
  191.   HTMLCHECK_UNINIT \
  192.   if (liens!=NULL) { \
  193.   for(i=lien_max-1;i>=0;i--) { \
  194.   if (liens[i]) { \
  195.   if (liens[i]->firstblock==1) { \
  196.   freet(liens[i]); \
  197.   liens[i]=NULL; \
  198.   } \
  199.   } \
  200.   } \
  201.   freet(liens); \
  202.   liens=NULL; \
  203.   } \
  204.   if (filters && filters[0]) { \
  205.   freet(filters[0]); filters[0]=NULL; \
  206.   } \
  207.   if (filters) { \
  208.   freet(filters); filters=NULL; \
  209.   } \
  210.   if (back) { \
  211.   int i; \
  212.   for(i=0;i<back_max;i++) { \
  213.   back_delete(&opt,&cache,back,i); \
  214.   } \
  215.   freet(back); back=NULL;  \
  216.   } \
  217.   checkrobots_free(&robots);\
  218.   if (cache.use) { freet(cache.use); cache.use=NULL; } \
  219.   if (cache.dat) { fclose(cache.dat); cache.dat=NULL; }  \
  220.   if (cache.ndx) { fclose(cache.ndx); cache.ndx=NULL; } \
  221.   if (cache.zipOutput) { \
  222.     zipClose(cache.zipOutput, "Created by HTTrack Website Copier/"HTTRACK_VERSION); \
  223.     cache.zipOutput = NULL; \
  224.   } \
  225.   if (cache.zipInput) { \
  226.     unzClose(cache.zipInput); \
  227.     cache.zipInput = NULL; \
  228.   } \
  229.   if (cache.olddat) { fclose(cache.olddat); cache.olddat=NULL; } \
  230.   if (cache.lst) { fclose(cache.lst); cache.lst=NULL; } \
  231.   if (cache.txt) { fclose(cache.txt); cache.txt=NULL; } \
  232.   if (opt.log) fflush(opt.log); \
  233.   if (opt.errlog) fflush(opt.errlog);\
  234.   if (makestat_fp) { fclose(makestat_fp); makestat_fp=NULL; } \
  235.   if (maketrack_fp){ fclose(maketrack_fp); maketrack_fp=NULL; } \
  236.   if (opt.accept_cookie) cookie_save(opt.cookie,fconcat(opt.path_log,"cookies.txt")); \
  237.   if (makeindex_fp) { fclose(makeindex_fp); makeindex_fp=NULL; } \
  238.   if (cache_hashtable) { inthash_delete(&cache_hashtable); } \
  239.   if (cache_tests)     { inthash_delete(&cache_tests); } \
  240.   if (template_header) { freet(template_header); template_header=NULL; } \
  241.   if (template_body)   { freet(template_body); template_body=NULL; } \
  242.   if (template_footer) { freet(template_footer); template_footer=NULL; } \
  243.   clearCallbacks(&opt.state.callbacks); \
  244.   /*structcheck_init(-1);*/ \
  245. } while(0)
  246. #define XH_uninit do { XH_extuninit; if (r.adr) { freet(r.adr); r.adr=NULL; } } while(0)
  247.  
  248. // Enregistrement d'un lien:
  249. // on calcule la taille nΘcessaire: taille des 3 chaεnes α stocker (taille forcΘe paire, plus 2 octets de sΘcuritΘ)
  250. // puis on vΘrifie qu'on a assez de marge dans le buffer - sinon on en rΘalloue un autre
  251. // enfin on Θcrit α l'adresse courante du buffer, qu'on incrΘmente. on dΘcrΘmente la taille dispo d'autant ensuite
  252. // codebase: si non nul et si .class stockee on le note pour chemin primaire pour classes
  253. // FA,FS: former_adr et former_fil, lien original
  254. #if HTS_HASH
  255. #define liens_record_sav_len(A) 
  256. #else
  257. #define liens_record_sav_len(A) (A)->sav_len=strlen((A)->sav)
  258. #endif
  259.  
  260. #define liens_record(A,F,S,FA,FF,NORM) { \
  261. int notecode=0; \
  262. int lienurl_len=((sizeof(lien_url)+HTS_ALIGN-1)/HTS_ALIGN)*HTS_ALIGN,\
  263.   adr_len=strlen(A),\
  264.   fil_len=strlen(F),\
  265.   sav_len=strlen(S),\
  266.   cod_len=0,\
  267.   former_adr_len=strlen(FA),\
  268.   former_fil_len=strlen(FF); \
  269. if (former_adr_len>0) {\
  270.   former_adr_len=(former_adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  271.   former_fil_len=(former_fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  272. } else former_adr_len=former_fil_len=0;\
  273. if (strlen(F)>6) if (strnotempty(codebase)) if (strfield(F+strlen(F)-6,".class")) { notecode=1; \
  274. cod_len=strlen(codebase); cod_len=(cod_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; } \
  275. adr_len=(adr_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; fil_len=(fil_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; sav_len=(sav_len/HTS_ALIGN)*HTS_ALIGN+HTS_ALIGN*2; \
  276. if ((int) lien_size < (int) (adr_len+fil_len+sav_len+cod_len+former_adr_len+former_fil_len+lienurl_len)) { \
  277. lien_buffer=(char*) ((void*) calloct(add_tab_alloc,1)); \
  278. lien_size=add_tab_alloc; \
  279. if (lien_buffer!=NULL) { \
  280. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  281. liens[lien_tot]->firstblock=1; \
  282. } \
  283. } else { \
  284. liens[lien_tot]=(lien_url*) (void*) lien_buffer; lien_buffer+=lienurl_len; lien_size-=lienurl_len; \
  285. liens[lien_tot]->firstblock=0; \
  286. } \
  287. if (liens[lien_tot]!=NULL) { \
  288. liens[lien_tot]->adr=lien_buffer; lien_buffer+=adr_len; lien_size-=adr_len; \
  289. liens[lien_tot]->fil=lien_buffer; lien_buffer+=fil_len; lien_size-=fil_len; \
  290. liens[lien_tot]->sav=lien_buffer; lien_buffer+=sav_len; lien_size-=sav_len; \
  291. liens[lien_tot]->cod=NULL; \
  292. if (notecode) { liens[lien_tot]->cod=lien_buffer; lien_buffer+=cod_len; lien_size-=cod_len; strcpybuff(liens[lien_tot]->cod,codebase); } \
  293. if (former_adr_len>0) {\
  294. liens[lien_tot]->former_adr=lien_buffer; lien_buffer+=former_adr_len; lien_size-=former_adr_len; \
  295. liens[lien_tot]->former_fil=lien_buffer; lien_buffer+=former_fil_len; lien_size-=former_fil_len; \
  296. strcpybuff(liens[lien_tot]->former_adr,FA); \
  297. strcpybuff(liens[lien_tot]->former_fil,FF); \
  298. }\
  299. strcpybuff(liens[lien_tot]->adr,A); \
  300. strcpybuff(liens[lien_tot]->fil,F); \
  301. strcpybuff(liens[lien_tot]->sav,S); \
  302. liens_record_sav_len(liens[lien_tot]); \
  303. hash_write(hashptr,lien_tot,NORM);  \
  304. } \
  305. }
  306.  
  307.  
  308. #define HT_INDEX_END do { \
  309. if (!makeindex_done) { \
  310. if (makeindex_fp) { \
  311.   char BIGSTK tempo[1024]; \
  312.   if (makeindex_links == 1) { \
  313.     sprintf(tempo,"<meta HTTP-EQUIV=\"Refresh\" CONTENT=\"0; URL=%s\">"CRLF,makeindex_firstlink); \
  314.   } else \
  315.     tempo[0]='\0'; \
  316.   fprintf(makeindex_fp,template_footer, \
  317.     "<!-- Mirror and index made by HTTrack Website Copier/"HTTRACK_VERSION" "HTTRACK_AFF_AUTHORS" -->", \
  318.     tempo \
  319.     ); \
  320.   fflush(makeindex_fp); \
  321.   fclose(makeindex_fp);  /* α ne pas oublier sinon on passe une nuit blanche */  \
  322.   makeindex_fp=NULL; \
  323.   usercommand(&opt,0,NULL,fconcat(opt.path_html,"index.html"),"","");  \
  324. } \
  325. } \
  326. makeindex_done=1;    /* ok c'est fait */  \
  327. } while(0)
  328.  
  329.  
  330.  
  331.  
  332. // DΘbut de httpmirror, robot
  333. // url1 peut Ωtre multiple
  334. int httpmirror(char* url1,httrackp* ptropt) {
  335.   httrackp BIGSTK opt;         // structure d'options
  336.   char* primary=NULL;          // premiΦre page, contenant les liens α scanner
  337.   int lien_tot=0;              // nombre de liens pour le moment
  338.   lien_url** liens=NULL;       // les pointeurs sur les liens
  339.   hash_struct hash;            // systΦme de hachage, accΘlΦre la recherche dans les liens
  340.   hash_struct* hashptr = &hash;
  341.   t_cookie BIGSTK cookie;             // gestion des cookies
  342.   int lien_max=0;
  343.   int lien_size=0;        // octets restants dans buffer liens dispo
  344.   char* lien_buffer=NULL; // buffer liens actuel
  345.   int add_tab_alloc=256000;    // +256K de liens α chaque fois
  346.   //char* tab_alloc=NULL;
  347.   int ptr;             // pointeur actuel sur les liens
  348.   //
  349.   int numero_passe=0;  // deux passes pour html puis images
  350.   int back_max=0;      // fichiers qui peuvent Ωtre en local
  351.   lien_back* back=NULL; // backing en local
  352.   htsblk BIGSTK r;            // retour de certaines fonctions
  353.   TStamp lastime=0;    // pour affichage infos de tmp en tmp
  354.   // pour les stats, nombre de fichiers & octets Θcrits
  355.   LLint stat_fragment=0;  // pour la fragmentation
  356.   //TStamp istat_timestart;   // dΘpart pour calcul instantannΘ
  357.   //
  358.   TStamp last_info_shell=0;
  359.   int info_shell=0;
  360.   // filtres
  361.   char** filters = NULL;
  362.   //int filter_max=0;
  363.   int filptr=0;
  364.   //
  365.   int makeindex_done=0;  // lorsque l'index sera fait
  366.   FILE* makeindex_fp=NULL;
  367.   int makeindex_links=0;
  368.   char BIGSTK makeindex_firstlink[HTS_URLMAXSIZE*2];
  369.   // statistiques (mode #Z)
  370.   FILE* makestat_fp=NULL;    // fichier de stats taux transfert
  371.   FILE* maketrack_fp=NULL;   // idem pour le tracking
  372.   TStamp makestat_time=0;    // attente (secondes)
  373.   LLint makestat_total=0;    // repΦre du nombre d'octets transfΘrΘs depuis denriΦre stat
  374.   int makestat_lnk=0;        // idem, pour le nombre de liens
  375.   //
  376.   char BIGSTK codebase[HTS_URLMAXSIZE*2];  // base pour applet java
  377.   char BIGSTK base[HTS_URLMAXSIZE*2];      // base pour les autres fichiers
  378.   //
  379.   cache_back BIGSTK cache;
  380.   robots_wizard BIGSTK robots;    // gestion robots.txt
  381.   inthash cache_hashtable=NULL;
  382.   inthash cache_tests=NULL;
  383.   int cache_hash_size=0;
  384.   //
  385.   char *template_header=NULL,*template_body=NULL,*template_footer=NULL;
  386.   //
  387.   opt = *ptropt;
  388.   //
  389.   codebase[0]='\0'; base[0]='\0';
  390.   //
  391.   cookie.auth.next=NULL;
  392.   cookie.auth.auth[0]=cookie.auth.prefix[0]='\0';
  393.   //
  394.  
  395.   // noter heure actuelle de dΘpart en secondes
  396.   memset(&HTS_STAT, 0, sizeof(HTS_STAT));
  397.   HTS_STAT.stat_timestart=time_local();
  398.   //istat_timestart=stat_timestart;
  399.   HTS_STAT.istat_timestart[0]=HTS_STAT.istat_timestart[1]=mtime_local();
  400.   /* reset stats */
  401.   HTS_STAT.HTS_TOTAL_RECV=0;
  402.   HTS_STAT.istat_bytes[0]=HTS_STAT.istat_bytes[1]=0;
  403.   /*
  404.   if (opt.aff_progress)
  405.     lastime=HTS_STAT.stat_timestart;
  406.     */
  407.   if (opt.shell) {
  408.     last_info_shell=HTS_STAT.stat_timestart;
  409.   }
  410.   if ((opt.makestat) || (opt.maketrack)){
  411.     makestat_time=HTS_STAT.stat_timestart;
  412.   }
  413.   // initialiser compteur erreurs
  414.   fspc(NULL,NULL);
  415.  
  416.   // init external modules
  417.   htspe_init();
  418.  
  419.   // initialiser cookie
  420.   if (opt.accept_cookie) {
  421.     opt.cookie=&cookie;
  422.     cookie.max_len=30000;       // max len
  423.     strcpybuff(cookie.data,"");
  424.     // Charger cookies.txt par dΘfaut ou cookies.txt du miroir
  425.     cookie_load(opt.cookie,opt.path_log,"cookies.txt");
  426.     cookie_load(opt.cookie,"","cookies.txt");
  427.   } else
  428.     opt.cookie=NULL;
  429.  
  430.   // initialiser exit_xh
  431.   exit_xh=0;          // sortir prΘmaturΘment (var globale)
  432.  
  433.   // initialiser usercommand
  434.   usercommand(&opt,opt.sys_com_exec,opt.sys_com,"","","");
  435.  
  436.   // initialiser structcheck
  437.   // structcheck_init(1);
  438.  
  439.   // initialiser tableau options accessible par d'autres fonctions (signal)
  440.   hts_declareoptbuffer(&opt);
  441.  
  442.   // initialiser verif_backblue
  443.   verif_backblue(&opt,NULL);
  444.   verif_external(0,0);
  445.   verif_external(1,0);
  446.  
  447.   // et templates html
  448.   template_header=readfile_or(fconcat(opt.path_bin,"templates/index-header.html"),HTS_INDEX_HEADER);
  449.   template_body=readfile_or(fconcat(opt.path_bin,"templates/index-body.html"),HTS_INDEX_BODY);
  450.   template_footer=readfile_or(fconcat(opt.path_bin,"templates/index-footer.html"),HTS_INDEX_FOOTER);
  451.  
  452.   // initialiser mimedefs
  453.   get_userhttptype(1,opt.mimedefs,NULL);
  454.  
  455.   // Initialiser indexation
  456.   if (opt.kindex)
  457.     index_init(opt.path_html);
  458.  
  459.   // effacer bloc cache
  460.   memset(&cache, 0, sizeof(cache_back));
  461.   cache.type=opt.cache;  // cache?
  462.   cache.errlog=opt.errlog;  // err log?
  463.   cache.ptr_ant=cache.ptr_last=0;   // pointeur pour anticiper
  464.  
  465.   // initialiser hash cache
  466.   if (!cache_hash_size) 
  467.     cache_hash_size=HTS_HASH_SIZE;
  468.   cache_hashtable=inthash_new(cache_hash_size);
  469.   cache_tests=inthash_new(cache_hash_size);
  470.   if (cache_hashtable==NULL || cache_tests==NULL) {
  471.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  472.     filters[0]=NULL; back_max=0;    // uniquement a cause du warning de XH_extuninit
  473.     XH_extuninit;
  474.     return 0;
  475.   }
  476.   inthash_value_is_malloc(cache_tests, 1);     /* malloc */
  477.   cache.hashtable=(void*)cache_hashtable;      /* copy backcache hash */
  478.   cache.cached_tests=(void*)cache_tests;      /* copy of cache_tests */
  479.  
  480.   // initialiser cache DNS
  481.   _hts_lockdns(-999);
  482.   
  483.   // robots.txt
  484.   strcpybuff(robots.adr,"!");    // dummy
  485.   robots.token[0]='\0';
  486.   robots.next=NULL;          // suivant
  487.   opt.robotsptr = &robots;
  488.   
  489.   // effacer filters
  490.   opt.maxfilter = maximum(opt.maxfilter, 128);
  491.   if (filters_init(&filters, opt.maxfilter, 0) == 0) {
  492.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  493.     back_max=0;    // uniquement a cause du warning de XH_extuninit
  494.     XH_extuninit;
  495.     return 0;
  496.   }
  497.   opt.filters.filters=&filters;
  498.   //
  499.   opt.filters.filptr=&filptr;
  500.   //opt.filters.filter_max=&filter_max;
  501.   
  502.   // hash table
  503.   opt.hash = &hash;
  504.  
  505.   // tableau de pointeurs sur les liens
  506.   lien_max=maximum(opt.maxlink,32);
  507.   liens=(lien_url**) malloct(lien_max*sizeof(lien_url*));   // tableau de pointeurs sur les liens
  508.   if (liens==NULL) {
  509.     printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  510.     //XH_uninit;
  511.     return 0;
  512.   } else {
  513.     int i;
  514.     for(i=0;i<lien_max;i++) {
  515.       liens[i]=NULL;     
  516.     }
  517.   }
  518.   // initialiser ptr et lien_tot
  519.   ptr=0;
  520.   lien_tot=0;
  521. #if HTS_HASH
  522.   // initialiser hachage
  523.   {
  524.     int i;
  525.     for(i=0;i<HTS_HASH_SIZE;i++)
  526.       hash.hash[0][i]=hash.hash[1][i]=hash.hash[2][i] = -1;    // pas d'entrΘes
  527.     hash.liens = liens;
  528.     hash.max_lien=0;
  529.   }
  530. #endif
  531.  
  532.   
  533.   // copier adresse(s) dans liste des adresses
  534.   {
  535.     char *a=url1;
  536.     int primary_len=8192;
  537.     if (strnotempty(opt.filelist)) {
  538.       primary_len+=max(0,fsize(opt.filelist)*2);
  539.     }
  540.     primary_len+=strlen(url1)*2;
  541.  
  542.     // crΘation de la premiΦre page, qui contient les liens de base α scanner
  543.     // c'est plus propre et plus logique que d'entrer α la main les liens dans la pile
  544.     // on bΘnΘficie ainsi des vΘrifications et des tests du robot pour les liens "primaires"
  545.     primary=(char*) malloct(primary_len); 
  546.     if (primary) {
  547.       primary[0]='\0';
  548.     } else {
  549.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  550.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  551.       XH_extuninit;
  552.       return 0;
  553.     }
  554.     
  555.     while(*a) {
  556.       int i;
  557.       int joker=0;
  558.  
  559.       // vΘrifier qu'il n'y a pas de * dans l'url
  560.       if (*a=='+')
  561.         joker=1;
  562.       else if (*a=='-')
  563.         joker=1;
  564.       
  565.       if (joker) {    // joker ou filters
  566.         //char* p;
  567.         char BIGSTK tempo[HTS_URLMAXSIZE*2];
  568.         int type; int plus=0;
  569.  
  570.         // noter joker (dans b)
  571.         if (*a=='+') {  // champ +
  572.           type=1; plus=1; a++;
  573.         } else if (*a=='-') {  // champ forbidden[]
  574.           type=0; a++;
  575.         } else {  // champ + avec joker sans doute
  576.           type=1;
  577.         }
  578.  
  579.         // recopier prochaine chaine (+ ou -)
  580.         i=0;
  581.         while((*a!=0) && (!isspace((unsigned char)*a))) { tempo[i++]=*a; a++; }  
  582.         tempo[i++]='\0';
  583.         while(isspace((unsigned char)*a)) { a++; }
  584.  
  585.         // sauter les + sans rien aprΦs..
  586.         if (strnotempty(tempo)) {
  587.           if ((plus==0) && (type==1)) {  // implicite: *www.edf.fr par exemple
  588.             if (tempo[strlen(tempo)-1]!='*') {
  589.               strcatbuff(tempo,"*");  // ajouter un *
  590.             }
  591.           }
  592.           if (type)
  593.             strcpybuff(filters[filptr],"+");
  594.           else
  595.             strcpybuff(filters[filptr],"-");
  596.           /*
  597.           if (strfield(tempo,"http://"))
  598.             strcatbuff(filters[filptr],tempo+7);        // ignorer http://
  599.           else if (strfield(tempo,"ftp://"))
  600.             strcatbuff(filters[filptr],tempo+6);        // ignorer ftp://
  601.           else
  602.           */
  603.           strcatbuff(filters[filptr],tempo);
  604.           filptr++;
  605.           
  606.           /* sanity check */
  607.           if (filptr + 1 >= opt.maxfilter) {
  608.             opt.maxfilter += HTS_FILTERSINC;
  609.             if (filters_init(&filters, opt.maxfilter, HTS_FILTERSINC) == 0) {
  610.               printf("PANIC! : Too many filters : >%d [%d]\n",filptr,__LINE__);
  611.               if (opt.errlog) {
  612.                 fprintf(opt.errlog,LF"Too many filters, giving up..(>%d)"LF,filptr);
  613.                 fprintf(opt.errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  614.                 test_flush;
  615.               }
  616.               back_max=0;    // uniquement a cause du warning de XH_extuninit
  617.               XH_extuninit;
  618.               return 0;
  619.             }
  620.             //opt.filters.filters=filters;
  621.           }
  622.  
  623.         }
  624.         
  625.       } else {    // adresse normale
  626.         char BIGSTK url[HTS_URLMAXSIZE*2];
  627.         // prochaine adresse
  628.         i=0;
  629.         while((*a!=0) && (!isspace((unsigned char)*a))) { url[i++]=*a; a++; }  
  630.         while(isspace((unsigned char)*a)) { a++; }
  631.         url[i++]='\0';
  632.  
  633.         //strcatbuff(primary,"<PRIMARY=\"");
  634.         if (strstr(url,":/")==NULL)
  635.           strcatbuff(primary,"http://");
  636.         strcatbuff(primary,url);
  637.         //strcatbuff(primary,"\">");
  638.         strcatbuff(primary,"\n");
  639.       }
  640.     }  // while
  641.  
  642.     /* load URL file list */
  643.     /* OPTIMIZED for fast load */
  644.     if (strnotempty(opt.filelist)) {
  645.       char* filelist_buff=NULL;
  646.       INTsys filelist_sz=fsize(opt.filelist);
  647.       if (filelist_sz>0) {
  648.         FILE* fp=fopen(opt.filelist,"rb");
  649.         if (fp) {
  650.           filelist_buff=malloct(filelist_sz + 2);
  651.           if (filelist_buff) {
  652.             if ((INTsys)fread(filelist_buff,1,filelist_sz,fp) != filelist_sz) {
  653.               freet(filelist_buff);
  654.               filelist_buff=NULL;
  655.             } else {
  656.               *(filelist_buff + filelist_sz) = '\0';
  657.             }
  658.           }
  659.           fclose(fp);
  660.         }
  661.       }
  662.       
  663.       if (filelist_buff) {
  664.         int filelist_ptr=0;
  665.         int n=0;
  666.         char BIGSTK line[HTS_URLMAXSIZE*2];
  667.         char* primary_ptr = primary + strlen(primary);
  668.         while( filelist_ptr < filelist_sz ) {
  669.           int count=binput(filelist_buff+filelist_ptr,line,HTS_URLMAXSIZE);
  670.           filelist_ptr+=count;
  671.           if (count && line[0]) {
  672.             n++;
  673.             if (strstr(line,":/")==NULL) {
  674.               strcpybuff(primary_ptr, "http://");
  675.               primary_ptr += strlen(primary_ptr);
  676.             }
  677.             strcpybuff(primary_ptr, line);
  678.             primary_ptr += strlen(primary_ptr);
  679.             strcpybuff(primary_ptr, "\n");
  680.             primary_ptr += 1;
  681.           }
  682.         }
  683.         // fclose(fp);
  684.         if (opt.log!=NULL) {
  685.           fspc(opt.log,"info"); fprintf(opt.log,"%d links added from %s"LF,n,opt.filelist); test_flush;
  686.         }
  687.  
  688.         // Free buffer
  689.         freet(filelist_buff);
  690.       } else {
  691.         if (opt.errlog!=NULL) {
  692.           fspc(opt.errlog,"error"); fprintf(opt.errlog,"Could not include URL list: %s"LF,opt.filelist); test_flush;
  693.         }
  694.       }
  695.     }
  696.  
  697.  
  698.     // lien primaire
  699.     liens_record("primary","/primary",fslash(fconcat(opt.path_html,"index.html")),"","",opt.urlhack);
  700.     if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  701.       printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  702.       if (opt.errlog) {
  703.         fprintf(opt.errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  704.         test_flush;
  705.       }
  706.       back_max=0;    // uniquement a cause du warning de XH_extuninit
  707.       XH_extuninit;    // dΘsallocation mΘmoire & buffers
  708.       return 0;
  709.     }    
  710.     liens[lien_tot]->testmode=0;          // pas mode test
  711.     liens[lien_tot]->link_import=0;       // pas mode import
  712.     liens[lien_tot]->depth=opt.depth+1;   // lien de prioritΘ maximale
  713.     liens[lien_tot]->pass2=0;             // 1Φre passe
  714.     liens[lien_tot]->retry=opt.retry;     // lien de prioritΘ maximale
  715.     liens[lien_tot]->premier=lien_tot;    // premier lien, objet-pΦre=objet              
  716.     liens[lien_tot]->precedent=lien_tot;  // lien prΘcΘdent
  717.     lien_tot++;  
  718.  
  719.     // Initialiser cache
  720.     {
  721.       int backupXFR = htsMemoryFastXfr;
  722. #if HTS_ANALYSTE
  723.       _hts_in_html_parsing=4;
  724. #endif
  725.       if (!hts_htmlcheck_loop(NULL,0,0,0,lien_tot,0,NULL)) {
  726.         exit_xh=1;  // exit requested
  727.       }
  728.       htsMemoryFastXfr = 1;               /* fast load */
  729.       cache_init(&cache,&opt);
  730.       htsMemoryFastXfr = backupXFR;
  731. #if HTS_ANALYSTE
  732.       _hts_in_html_parsing=0;
  733. #endif
  734.     }
  735.  
  736.   }
  737.   
  738. #if BDEBUG==3
  739.   {
  740.     int i;
  741.     for(i=0;i<lien_tot;i++) {
  742.       printf("%d>%s%s as %s\n",i,liens[i]->adr,liens[i]->fil,liens[i]->sav);
  743.     }
  744.     for(i=0;i<filptr;i++) {
  745.       printf("%d>filters=%s\n",i,filters[i]);
  746.     }
  747.   }
  748. #endif
  749.    
  750.   // backing
  751.   //soc_max=opt.maxsoc;
  752.   if (opt.maxsoc>0) {
  753. #if BDEBUG==2
  754.     _CLRSCR;
  755. #endif
  756.     // Nombre de fichiers HTML pouvant Ωtre prΘsents en mΘmoire de maniΦre simultannΘe
  757.     // On prΘvoit large: les fichiers HTML ne prennent que peu de place en mΘmoire, et les
  758.     // fichiers non html sont sauvΘs en direct sur disque.
  759.     // --> 1024 entrΘes + 32 entrΘes par socket en supplΘment
  760.     back_max=opt.maxsoc*32+1024;
  761.     //back_max=opt.maxsoc*8+32;
  762.     back=(lien_back*) calloct((back_max+1),sizeof(lien_back));
  763.     if (back==NULL) {
  764.       if (opt.errlog)
  765.         fprintf(opt.errlog,"Not enough memory, can not allocate %d bytes"LF,(int)((opt.maxsoc+1)*sizeof(lien_back)));
  766.       return 0;
  767.     } else {    // copier buffer-location & effacer
  768.       int i;
  769.       for(i=0;i<back_max;i++){
  770.         back[i].r.location=back[i].location_buffer;
  771.         back[i].status=-1;
  772.         back[i].r.soc=INVALID_SOCKET;
  773.       }
  774.     }
  775.   }
  776.  
  777.  
  778.   // flush
  779.   test_flush;
  780.  
  781.   // statistiques
  782.   if (opt.makestat) {
  783.     makestat_fp=fopen(fconcat(opt.path_log,"hts-stats.txt"),"wb");
  784.     if (makestat_fp != NULL) {
  785.       fprintf(makestat_fp,"HTTrack statistics report, every minutes"LF LF);
  786.       fflush(makestat_fp);
  787.     }
  788.   }
  789.  
  790.   // tracking -- dΘbuggage
  791.   if (opt.maketrack) {
  792.     maketrack_fp=fopen(fconcat(opt.path_log,"hts-track.txt"),"wb");
  793.     if (maketrack_fp != NULL) {
  794.       fprintf(maketrack_fp,"HTTrack tracking report, every minutes"LF LF);
  795.       fflush(maketrack_fp);
  796.     }
  797.   }
  798.  
  799.   // on n'a pas de liens!! (exemple: httrack www.* impossible sans dΘpart..)
  800.   if (lien_tot<=0) {
  801.     if (opt.errlog) {
  802.       fprintf(opt.errlog,"Error! You MUST specify at least one complete URL, and not only wildcards!"LF);
  803.     }
  804.   }
  805.  
  806.   /* Send options to callback functions */
  807. #if HTS_ANALYSTE
  808.   hts_htmlcheck_chopt(&opt);
  809. #endif
  810.  
  811.   // attendre une certaine heure..
  812.   if (opt.waittime>0) {
  813.     int rollover=0;
  814.     int ok=0;
  815.     {
  816.       TStamp tl=0;
  817.       time_t tt;
  818.       struct tm* A;
  819.       tt=time(NULL);
  820.       A=localtime(&tt);
  821.       tl+=A->tm_sec;
  822.       tl+=A->tm_min*60;
  823.       tl+=A->tm_hour*60*60;
  824.       if (tl>opt.waittime)  // attendre minuit
  825.         rollover=1;
  826.     }
  827.  
  828.     // attendre..
  829.     _hts_in_html_parsing=5;
  830.     do {
  831.       TStamp tl=0;
  832.       time_t tt;
  833.       struct tm* A;
  834.       tt=time(NULL);
  835.       A=localtime(&tt);
  836.       tl+=A->tm_sec;
  837.       tl+=A->tm_min*60;
  838.       tl+=A->tm_hour*60*60;
  839.  
  840.       if (rollover) {
  841.         if (tl<=opt.waittime)
  842.           rollover=0;  // attendre heure
  843.       } else {
  844.         if (tl>opt.waittime)
  845.           ok=1;  // ok!
  846.       }
  847.       
  848. #if HTS_ANALYSTE
  849.       {  
  850.         int r;
  851.         if (rollover)
  852.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl+24*3600),NULL);
  853.         else
  854.           r=hts_htmlcheck_loop(back,back_max,0,0,lien_tot,(int) (opt.waittime-tl),NULL);
  855.         if (!r) {
  856.           exit_xh=1;  // exit requested
  857.           ok=1;          
  858.         } else
  859.           Sleep(100);
  860.       }
  861. #endif
  862.     } while(!ok);    
  863.     _hts_in_html_parsing=0;
  864.     
  865.     // note: recopie de plus haut
  866.     // noter heure actuelle de dΘpart en secondes
  867.     HTS_STAT.stat_timestart=time_local();
  868.     /*
  869.     if (opt.aff_progress)
  870.       lastime=HTS_STAT.stat_timestart;
  871.       */
  872.     if (opt.shell) {
  873.       last_info_shell=HTS_STAT.stat_timestart;
  874.     }
  875.     if ((opt.makestat) || (opt.maketrack)){
  876.       makestat_time=HTS_STAT.stat_timestart;
  877.     }
  878.  
  879.  
  880.   }  
  881.   /* Info for wrappers */
  882.   if ( (opt.debug>0) && (opt.log!=NULL) ) {
  883.     fspc(opt.log,"info"); fprintf(opt.log,"engine: start"LF);
  884.   }
  885. #if HTS_ANALYSTE
  886.   if (!hts_htmlcheck_start(&opt)) {
  887.     XH_extuninit;
  888.     return 1;
  889.   }
  890.   set_wrappers();   // _start() is allowed to set other wrappers
  891. #endif
  892.   
  893.  
  894.   // ------------------------------------------------------------
  895.  
  896.   // ------------------------------------------------------------
  897.   // Boucle gΘnΘrale de parcours des liens
  898.   // ------------------------------------------------------------
  899.   do {
  900.     int error=0;          // si error alors sauter
  901.     int store_errpage=0;  // c'est une erreur mais on enregistre le html
  902.     char BIGSTK loc[HTS_URLMAXSIZE*2];    // adresse de relocation
  903.  
  904.     // Ici on charge le fichier (html, gif..) en mΘmoire
  905.     // Les HTMLs sont traitΘs (si leur prioritΘ est suffisante)
  906.  
  907.     // effacer r
  908.     memset(&r, 0, sizeof(htsblk)); r.soc=INVALID_SOCKET;
  909.     r.location=loc;    // en cas d'erreur 3xx (moved)
  910.     // recopier proxy
  911.     memcpy(&(r.req.proxy), &opt.proxy, sizeof(opt.proxy));
  912.     // et user-agent
  913.     strcpybuff(r.req.user_agent,opt.user_agent);
  914.     strcpybuff(r.req.referer,opt.referer);
  915.     strcpybuff(r.req.from,opt.from);
  916.     strcpybuff(r.req.lang_iso,opt.lang_iso);
  917.     r.req.user_agent_send=opt.user_agent_send;
  918.  
  919.     if (!error) {
  920.       
  921.       // Skip empty/invalid/done in background
  922.       if (liens[ptr]) {
  923.         while (  (liens[ptr]) && (
  924.                     ( ((urladr != NULL)?(urladr):(" "))[0]=='!') ||
  925.                     ( ((urlfil != NULL)?(urlfil):(" "))[0]=='\0') ||
  926.                     ( (liens[ptr]->pass2 == -1) )
  927.                  )
  928.                ) {  // sauter si lien annulΘ (ou fil vide)
  929.           if ((opt.debug>1) && (opt.log!=NULL)) {
  930.             fspc(opt.log,"debug"); fprintf(opt.log,"link #%d seems ready, skipping: %s%s.."LF,ptr,((urladr != NULL)?(urladr):(" ")),((urlfil != NULL)?(urlfil):(" ")));
  931.             test_flush;
  932.           }
  933.           ptr++;
  934.         }
  935.       }
  936.       if (liens[ptr]) {    // on a qq chose α rΘcupΘrer?
  937.  
  938.         if ( (opt.debug>1) && (opt.log!=NULL) ) {
  939.           fspc(opt.log,"debug"); fprintf(opt.log,"Wait get: %s%s"LF,urladr,urlfil);
  940.           test_flush;
  941. #if DEBUG_ROBOTS
  942.           if (strcmp(urlfil,"/robots.txt") == 0) {
  943.             printf("robots.txt detected\n");
  944.           }
  945. #endif
  946.         }    
  947.         // ------------------------------------------------------------
  948.         // DEBUT --RECUPERATION LIEN---
  949.         if (ptr==0) {              // premier lien α parcourir: lien primaire construit avant
  950.           r.adr=primary; primary=NULL;
  951.           r.statuscode=200;
  952.           r.size=strlen(r.adr);
  953.           r.soc=INVALID_SOCKET;
  954.           strcpybuff(r.contenttype,"text/html");
  955.         /*} else if (opt.maxsoc<=0) {   // fichiers 1 α 1 en attente (pas de backing)
  956.           // charger le fichier en mΘmoire tout bΩtement
  957.           r=xhttpget(urladr,urlfil);
  958.           //
  959.         */
  960.         } else {    // backing, multiples sockets
  961.           
  962.           
  963.           /*
  964.             **************************************
  965.             Get the next link, waiting for other files, handling external callbacks
  966.           */
  967.           {
  968.             char BIGSTK buff_err_msg[1024];
  969.             htsmoduleStruct BIGSTK str;
  970.             htsmoduleStructExtended BIGSTK stre;
  971.             buff_err_msg[0] = '\0';
  972.             memset(&str, 0, sizeof(str));
  973.             memset(&stre, 0, sizeof(stre));
  974.             /* */
  975.             str.err_msg = buff_err_msg;
  976.             str.filename = savename;
  977.             str.mime = r.contenttype;
  978.             str.url_host = urladr;
  979.             str.url_file = urlfil;
  980.             str.size = (int) r.size;
  981.             /* */
  982.             str.addLink = htsAddLink;
  983.             /* */
  984.             str.liens = liens;
  985.             str.opt = &opt;
  986.             str.back = back;
  987.             str.back_max = back_max;
  988.             str.cache = &cache;
  989.             str.hashptr = hashptr;
  990.             str.numero_passe = numero_passe;
  991.             str.add_tab_alloc = add_tab_alloc;
  992.             /* */
  993.             str.lien_tot_ = &lien_tot;
  994.             str.ptr_ = &ptr;
  995.             str.lien_size_ = &lien_size;
  996.             str.lien_buffer_ = &lien_buffer;
  997.             /* */
  998.             /* */
  999.             stre.r_ = &r;
  1000.             /* */
  1001.             stre.error_ = &error;
  1002.             stre.exit_xh_ = &exit_xh;
  1003.             stre.store_errpage_ = &store_errpage;
  1004.             /* */
  1005.             stre.base = base;
  1006.             stre.codebase = codebase;
  1007.             /* */
  1008.             stre.filters_ = &filters;
  1009.             stre.filptr_ = &filptr;
  1010.             stre.robots_ = &robots;
  1011.             stre.hash_ = &hash;
  1012.             stre.lien_max_ = &lien_max;
  1013.             /* */
  1014.             stre.makeindex_done_ = &makeindex_done;
  1015.             stre.makeindex_fp_ = &makeindex_fp;
  1016.             stre.makeindex_links_ = &makeindex_links;
  1017.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1018.             /* */
  1019.             stre.template_header_ = template_header;
  1020.             stre.template_body_ = template_body;
  1021.             stre.template_footer_ = template_footer;
  1022.             /* */
  1023.             stre.stat_fragment_ = &stat_fragment;
  1024.             stre.makestat_time = makestat_time;
  1025.             stre.makestat_fp = makestat_fp;
  1026.             stre.makestat_total_ = &makestat_total;
  1027.             stre.makestat_lnk_ = &makestat_lnk;
  1028.             stre.maketrack_fp = maketrack_fp;
  1029.             /* FUNCTION DEPENDANT */
  1030.             stre.loc_ = loc;
  1031.             stre.last_info_shell_ = &last_info_shell;
  1032.             stre.info_shell_ = &info_shell;
  1033.  
  1034.             /* Parse */
  1035.             switch(hts_mirror_wait_for_next_file(&str, &stre)) {
  1036.             case -1:
  1037.               XH_uninit;
  1038.               return -1;
  1039.               break;
  1040.             case 2:
  1041.               // Jump to 'continue'
  1042.               // This is one of the very very rare cases where goto
  1043.               // is acceptable
  1044.               // A supplemental flag and if( ) { } would be really messy
  1045.               goto jump_if_done;
  1046.             }
  1047.             
  1048.           }
  1049.           
  1050.           
  1051.         }
  1052.         // FIN --RECUPERATION LIEN--- 
  1053.         // ------------------------------------------------------------
  1054.         
  1055.         
  1056.         
  1057.       } else {    // lien vide..
  1058.         if (opt.errlog && opt.debug > 0) {
  1059.           fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning, link #%d empty"LF,ptr); test_flush;
  1060.         }         
  1061.         error=1;
  1062.         goto jump_if_done;
  1063.       }  // test si url existe (non vide!)
  1064.       
  1065.  
  1066.  
  1067.       // ---tester taille a posteriori---
  1068.       // tester r.adr
  1069.       if (!error) {
  1070.         // erreur, pas de fichier chargΘ:
  1071.         if ((!r.adr) && (r.is_write==0) 
  1072.           && (r.statuscode!=301) 
  1073.           && (r.statuscode!=302) 
  1074.           && (r.statuscode!=303) 
  1075.           && (r.statuscode!=307) 
  1076.           && (r.statuscode!=412)
  1077.           && (r.statuscode!=416)
  1078.          ) { 
  1079.           // error=1;
  1080.           
  1081.           // peut Ωtre que le fichier Θtait trop gros?
  1082.           if ((istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))
  1083.            || (istoobig(r.totalsize,opt.maxfile_html,opt.maxfile_nonhtml,r.contenttype))) {
  1084.             error=0;
  1085.             if (opt.errlog) {
  1086.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Big file cancelled according to user's preferences: %s%s"LF,urladr,urlfil);
  1087.               test_flush;
  1088.             }
  1089.           }
  1090.           // // // error=1;    // ne pas traiter la suite -- euhh si finalement..
  1091.         }
  1092.       }
  1093.       // ---fin tester taille a posteriori---    
  1094.  
  1095.       
  1096.       // -------------------- 
  1097.       // BOGUS MIME TYPE HACK
  1098.       // Check if we have a bogus MIME type
  1099.       // example: 
  1100.       // Content-type="text/html"
  1101.       // and 
  1102.       // Content-disposition="foo.jpg"
  1103.       // --------------------
  1104.       if (!error) {
  1105.         if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1106.           if (r.adr) {    // Written file
  1107.             if ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1108.               || (may_be_hypertext_mime(r.contenttype, urlfil) && (r.adr) )  /* Is real media, .. */
  1109.               ) {
  1110.               if (strnotempty(r.cdispo)) {      // Content-disposition set!
  1111.                 if (ishtml(savename) == 0) {    // Non HTML!!
  1112.                   // patch it!
  1113.                   strcpybuff(r.contenttype,"application/octet-stream");
  1114.                 }
  1115.               }
  1116.             }
  1117.           }
  1118.         }
  1119.         
  1120.         // ------------------------------------
  1121.         // BOGUS MIME TYPE HACK II (the revenge)
  1122.         // Check if we have a bogus MIME type
  1123.         if ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1124.           || (may_be_hypertext_mime(r.contenttype, urlfil))  /* Is real media, .. */
  1125.           ) {
  1126.           if ((r.adr) && (r.size)) {
  1127.             unsigned int map[256];
  1128.             int i;
  1129.             unsigned int nspec = 0;
  1130.             map_characters((unsigned char*)r.adr, (unsigned int)r.size, (unsigned int*)map);
  1131.             for(i = 1 ; i < 32 ; i++) {   //  null chars ignored..
  1132.               if (!is_realspace(i) 
  1133.                 && i != 27        /* Damn you ISO2022-xx! */
  1134.                 ) {
  1135.                 nspec += map[i];
  1136.               }
  1137.             }
  1138.             /* On-the-fly UCS2 to ISO-8859-1 conversion (note: UCS2 should never be used on the net) */
  1139.             if (
  1140.               map[0] > r.size/10
  1141.               &&
  1142.               r.size % 2 == 0
  1143.               &&
  1144.               (
  1145.               ( ((unsigned char) r.adr[0]) == 0xff && ((unsigned char) r.adr[1]) == 0xfe)
  1146.               ||
  1147.               ( ((unsigned char) r.adr[0]) == 0xfe && ((unsigned char) r.adr[1]) == 0xff)
  1148.               )
  1149.               ) {
  1150.               int lost=0;
  1151.               int i;
  1152.               int swap = (r.adr[0] == 0xff);
  1153.               for(i = 0 ; i < r.size / 2 - 1 ; i++) {
  1154.                 unsigned int unic = 0;
  1155.                 if (swap)
  1156.                   unic = (r.adr[i*2 + 2] << 8) + r.adr[i*2 + 2 + 1];
  1157.                 else
  1158.                   unic = r.adr[i*2 + 2] + (r.adr[i*2 + 2 + 1] << 8);
  1159.                 if (unic <= 255)
  1160.                   r.adr[i] = (char) unic;
  1161.                 else {
  1162.                   r.adr[i] = '?';
  1163.                   lost++;
  1164.                 }
  1165.               }
  1166.               r.size = r.size / 2 - 1;
  1167.               r.adr[r.size] = '\0';
  1168.  
  1169.               if (opt.errlog) {
  1170.                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File %s%s converted from UCS2 to 8-bit, %d characters lost during conversion (better to use UTF-8)"LF, urladr, urlfil, lost);
  1171.                 test_flush;
  1172.               }
  1173.             } else if ((nspec > r.size / 100) && (nspec > 10)) {    // too many special characters
  1174.               strcpybuff(r.contenttype,"application/octet-stream");
  1175.               if (opt.errlog) {
  1176.                 fspc(opt.errlog,"warning"); fprintf(opt.errlog,"File not parsed, looks like binary: %s%s"LF,urladr,urlfil);
  1177.                 test_flush;
  1178.               }
  1179.             }
  1180.  
  1181.             /* This hack allows to avoid problems with parsing '\0' characters  */
  1182.             for(i = 0 ; i < r.size ; i++) {
  1183.               if (r.adr[i] == '\0') r.adr[i] = ' ';
  1184.             }
  1185.  
  1186.           }
  1187.  
  1188.  
  1189.         }
  1190.       }
  1191.       
  1192.       // -------------------- 
  1193.       // REAL MEDIA HACK
  1194.       // Check if we have to load locally the file
  1195.       // --------------------
  1196.       if (!error) {
  1197.         if (r.statuscode == 200) {    // OK (ou 304 en backing)
  1198.           if (r.adr==NULL) {    // Written file
  1199.             if (may_be_hypertext_mime(r.contenttype, urlfil)) {   // to parse!
  1200.               LLint sz;
  1201.               sz=fsize(savename);
  1202.               if (sz>0) {   // ok, exists!
  1203.                 if (sz < 8192) {   // ok, small file --> to parse!
  1204.                   FILE* fp=fopen(savename,"rb");
  1205.                   if (fp) {
  1206.                     r.adr=malloct((int)sz + 2);
  1207.                     if (r.adr) {
  1208.                       if (fread(r.adr,1,(INTsys)sz,fp) == sz) {
  1209.                         r.size=sz;
  1210.                       } else {
  1211.                         freet(r.adr);
  1212.                         r.size=0;
  1213.                         r.adr = NULL;
  1214.                         r.statuscode=-1;
  1215.                         strcpybuff(r.msg, ".RAM read error");
  1216.                       }
  1217.                       fclose(fp);
  1218.                       fp=NULL;
  1219.                       // remove (temporary) file!
  1220.                       remove(savename);
  1221.                     }
  1222.                     if (fp)
  1223.                       fclose(fp);
  1224.                   }
  1225.                 }
  1226.               }
  1227.             }
  1228.           }
  1229.         }
  1230.       }
  1231.       // EN OF REAL MEDIA HACK
  1232.       
  1233.  
  1234.       // ---stockage en cache---
  1235.       // stocker dans le cache?
  1236.       /*
  1237.       if (!error) {
  1238.         if (ptr>0) {
  1239.           if (liens[ptr]) {
  1240.             xxcache_mayadd(&opt,&cache,&r,urladr,urlfil,savename);
  1241.           } else
  1242.             error=1;
  1243.         }
  1244.       }
  1245.       */
  1246.       // ---fin stockage en cache---
  1247.       
  1248.       
  1249.       
  1250.       /*
  1251.          **************************************
  1252.          Check "Moved permanently" and other similar errors, retrying URLs if necessary and handling
  1253.          redirect pages.
  1254.       */
  1255.       if (!error) {
  1256.         char BIGSTK buff_err_msg[1024];
  1257.         htsmoduleStruct BIGSTK str;
  1258.         htsmoduleStructExtended BIGSTK stre;
  1259.         buff_err_msg[0] = '\0';
  1260.         memset(&str, 0, sizeof(str));
  1261.         memset(&stre, 0, sizeof(stre));
  1262.         /* */
  1263.         str.err_msg = buff_err_msg;
  1264.         str.filename = savename;
  1265.         str.mime = r.contenttype;
  1266.         str.url_host = urladr;
  1267.         str.url_file = urlfil;
  1268.         str.size = (int) r.size;
  1269.         /* */
  1270.         str.addLink = htsAddLink;
  1271.         /* */
  1272.         str.liens = liens;
  1273.         str.opt = &opt;
  1274.         str.back = back;
  1275.         str.back_max = back_max;
  1276.         str.cache = &cache;
  1277.         str.hashptr = hashptr;
  1278.         str.numero_passe = numero_passe;
  1279.         str.add_tab_alloc = add_tab_alloc;
  1280.         /* */
  1281.         str.lien_tot_ = &lien_tot;
  1282.         str.ptr_ = &ptr;
  1283.         str.lien_size_ = &lien_size;
  1284.         str.lien_buffer_ = &lien_buffer;
  1285.         /* */
  1286.         /* */
  1287.         stre.r_ = &r;
  1288.         /* */
  1289.         stre.error_ = &error;
  1290.         stre.exit_xh_ = &exit_xh;
  1291.         stre.store_errpage_ = &store_errpage;
  1292.         /* */
  1293.         stre.base = base;
  1294.         stre.codebase = codebase;
  1295.         /* */
  1296.         stre.filters_ = &filters;
  1297.         stre.filptr_ = &filptr;
  1298.         stre.robots_ = &robots;
  1299.         stre.hash_ = &hash;
  1300.         stre.lien_max_ = &lien_max;
  1301.         /* */
  1302.         stre.makeindex_done_ = &makeindex_done;
  1303.         stre.makeindex_fp_ = &makeindex_fp;
  1304.         stre.makeindex_links_ = &makeindex_links;
  1305.         stre.makeindex_firstlink_ = makeindex_firstlink;
  1306.         /* */
  1307.         stre.template_header_ = template_header;
  1308.         stre.template_body_ = template_body;
  1309.         stre.template_footer_ = template_footer;
  1310.         /* */
  1311.         stre.stat_fragment_ = &stat_fragment;
  1312.         stre.makestat_time = makestat_time;
  1313.         stre.makestat_fp = makestat_fp;
  1314.         stre.makestat_total_ = &makestat_total;
  1315.         stre.makestat_lnk_ = &makestat_lnk;
  1316.         stre.maketrack_fp = maketrack_fp;
  1317.         
  1318.         /* Parse */
  1319.         if (hts_mirror_check_moved(&str, &stre) != 0) {
  1320.           XH_uninit;
  1321.           return -1;
  1322.         }
  1323.         
  1324.       }
  1325.  
  1326.     }  // if !error
  1327.     
  1328.     if (!error) {
  1329. #if DEBUG_SHOWTYPES
  1330.       if (strstr(REG,r.contenttype)==NULL) {
  1331.         strcatbuff(REG,r.contenttype);
  1332.         strcatbuff(REG,"\n");
  1333.         printf("%s\n",r.contenttype);
  1334.         io_flush;
  1335.       }
  1336. #endif
  1337.       
  1338.  
  1339.       // ------------------------------------------------------
  1340.       // ok, fichier chargΘ localement
  1341.       // ------------------------------------------------------
  1342.       
  1343.       // VΘrificateur d'intΘgritΘ
  1344.       #if DEBUG_CHECKINT
  1345.       {
  1346.         int i;
  1347.         for(i=0;i<back_max;i++) {
  1348.           char si[256];
  1349.           sprintf(si,"Test global aprΦs back_wait, index %d",i);
  1350.           _CHECKINT(&back[i],si)
  1351.         }
  1352.       }
  1353.       #endif
  1354.  
  1355.  
  1356.       /* info: updated */
  1357.       /*
  1358.       if (ptr>0) {
  1359.         // "mis α jour"
  1360.         if ((!r.notmodified) && (opt.is_update) && (!store_errpage)) {    // page modifiΘe
  1361.           if (strnotempty(savename)) {
  1362.             HTS_STAT.stat_updated_files++;
  1363.             if (opt.log!=NULL) {
  1364.               //if ((opt.debug>0) && (opt.log!=NULL)) {
  1365.               fspc(opt.log,"info"); fprintf(opt.log,"File updated: %s%s"LF,urladr,urlfil);
  1366.               test_flush;
  1367.             }
  1368.           }
  1369.         } else {
  1370.           if (!store_errpage) {
  1371.             if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1372.               fspc(opt.log,"info"); fprintf(opt.log,"File recorded: %s%s"LF,urladr,urlfil);
  1373.               test_flush;
  1374.             }
  1375.           }
  1376.         }
  1377.       }
  1378.       */
  1379.       
  1380.       // ------------------------------------------------------
  1381.       // traitement (parsing)
  1382.       // ------------------------------------------------------
  1383.  
  1384.       // traiter
  1385.       if (
  1386.            ( (is_hypertext_mime(r.contenttype, urlfil))   /* Is HTML or Js, .. */
  1387.              || (may_be_hypertext_mime(r.contenttype, urlfil) && (r.adr) )  /* Is real media, .. */
  1388.            )
  1389.         && (liens[ptr]->depth>0)            /* Depth > 0 (recurse depth) */
  1390.         && (r.adr!=NULL)        /* HTML Data exists */
  1391.         && (r.size>0)           /* And not empty */
  1392.         && (!store_errpage)     /* Not an html error page */
  1393.         && (savename[0]!='\0')  /* Output filename exists */
  1394.         ) {    // ne traiter que le html si autorisΘ
  1395.         // -- -- -- --
  1396.         // Parsing HTML
  1397.         if (!error) {
  1398.           /* Info for wrappers */
  1399.           if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1400.             fspc(opt.log,"info"); fprintf(opt.log,"engine: check-html: %s%s"LF,urladr,urlfil);
  1401.           }
  1402.           {
  1403.             char BIGSTK buff_err_msg[1024];
  1404.             htsmoduleStruct BIGSTK str;
  1405.             htsmoduleStructExtended BIGSTK stre;
  1406.             buff_err_msg[0] = '\0';
  1407.             memset(&str, 0, sizeof(str));
  1408.             memset(&stre, 0, sizeof(stre));
  1409.             /* */
  1410.             str.err_msg = buff_err_msg;
  1411.             str.filename = savename;
  1412.             str.mime = r.contenttype;
  1413.             str.url_host = urladr;
  1414.             str.url_file = urlfil;
  1415.             str.size = (int) r.size;
  1416.             /* */
  1417.             str.addLink = htsAddLink;
  1418.             /* */
  1419.             str.liens = liens;
  1420.             str.opt = &opt;
  1421.             str.back = back;
  1422.             str.back_max = back_max;
  1423.             str.cache = &cache;
  1424.             str.hashptr = hashptr;
  1425.             str.numero_passe = numero_passe;
  1426.             str.add_tab_alloc = add_tab_alloc;
  1427.             /* */
  1428.             str.lien_tot_ = &lien_tot;
  1429.             str.ptr_ = &ptr;
  1430.             str.lien_size_ = &lien_size;
  1431.             str.lien_buffer_ = &lien_buffer;
  1432.             /* */
  1433.             /* */
  1434.             stre.r_ = &r;
  1435.             /* */
  1436.             stre.error_ = &error;
  1437.             stre.exit_xh_ = &exit_xh;
  1438.             stre.store_errpage_ = &store_errpage;
  1439.             /* */
  1440.             stre.base = base;
  1441.             stre.codebase = codebase;
  1442.             /* */
  1443.             stre.filters_ = &filters;
  1444.             stre.filptr_ = &filptr;
  1445.             stre.robots_ = &robots;
  1446.             stre.hash_ = &hash;
  1447.             stre.lien_max_ = &lien_max;
  1448.             /* */
  1449.             stre.makeindex_done_ = &makeindex_done;
  1450.             stre.makeindex_fp_ = &makeindex_fp;
  1451.             stre.makeindex_links_ = &makeindex_links;
  1452.             stre.makeindex_firstlink_ = makeindex_firstlink;
  1453.             /* */
  1454.             stre.template_header_ = template_header;
  1455.             stre.template_body_ = template_body;
  1456.             stre.template_footer_ = template_footer;
  1457.             /* */
  1458.             stre.stat_fragment_ = &stat_fragment;
  1459.             stre.makestat_time = makestat_time;
  1460.             stre.makestat_fp = makestat_fp;
  1461.             stre.makestat_total_ = &makestat_total;
  1462.             stre.makestat_lnk_ = &makestat_lnk;
  1463.             stre.maketrack_fp = maketrack_fp;
  1464.             
  1465.             /* Parse */
  1466.             if (htsparse(&str, &stre) != 0) {
  1467.               XH_uninit;
  1468.               return -1;
  1469.             }
  1470.  
  1471.  
  1472.           // I'll have to segment this part
  1473. // #include "htsparse.c"
  1474.  
  1475.  
  1476.           }
  1477.         }
  1478.         // Fin parsing HTML
  1479.         // -- -- -- --
  1480.  
  1481.  
  1482.       }  // si text/html
  1483.       // -- -- --
  1484.       else {    // sauver fichier quelconque
  1485.         // -- -- --
  1486.         // sauver fichier
  1487.  
  1488.  
  1489.         /* En cas d'erreur, vΘrifier que fichier d'erreur existe */
  1490.         if (strnotempty(savename) == 0) {           // chemin de sauvegarde existant
  1491.           if (strcmp(urlfil,"/robots.txt")==0) {    // pas robots.txt
  1492.             if (store_errpage) {                    // c'est une page d'erreur
  1493.               int create_html_warning=0;
  1494.               int create_gif_warning=0;
  1495.               switch (ishtml(urlfil)) {      /* pas fichier html */
  1496.               case 0:                        /* non html */
  1497.                 {
  1498.                   char buff[256];
  1499.                   guess_httptype(buff,urlfil);
  1500.                   if (strcmp(buff,"image/gif")==0)
  1501.                     create_gif_warning=1;
  1502.                 }
  1503.                 break;
  1504.               case 1:                        /* html */
  1505.                 if (!r.adr) {
  1506.                 }
  1507.                 break;
  1508.               default:                       /* don't know.. */
  1509.                 break;    
  1510.               }
  1511.               /* CrΘer message d'erreur ? */
  1512.               if (create_html_warning) {
  1513.                 char* adr=(char*)malloct(strlen(HTS_DATA_ERROR_HTML)+1100);
  1514.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1515.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating HTML warning file (%s)"LF,r.msg);
  1516.                   test_flush;
  1517.                 }
  1518.                 if (adr) {
  1519.                   if (r.adr) {
  1520.                     freet(r.adr);
  1521.                     r.adr=NULL;
  1522.                   }
  1523.                   sprintf(adr,HTS_DATA_ERROR_HTML,r.msg);
  1524.                   r.adr=adr;
  1525.                 }
  1526.               } else if (create_gif_warning) {
  1527.                 char* adr=(char*)malloct(HTS_DATA_UNKNOWN_GIF_LEN);
  1528.                 if ( (opt.debug>0) && (opt.log!=NULL) ) {
  1529.                   fspc(opt.log,"info"); fprintf(opt.log,"Creating GIF dummy file (%s)"LF,r.msg);
  1530.                   test_flush;
  1531.                 }
  1532.                 if (r.adr) {
  1533.                   freet(r.adr);
  1534.                   r.adr=NULL;
  1535.                 }
  1536.                 memcpy(adr, HTS_DATA_UNKNOWN_GIF, HTS_DATA_UNKNOWN_GIF_LEN);
  1537.                 r.adr=adr;
  1538.               }
  1539.             }
  1540.           }
  1541.         }
  1542.  
  1543.         if (strnotempty(savename) == 0) {    // pas de chemin de sauvegarde
  1544.           if (strcmp(urlfil,"/robots.txt")==0) {    // robots.txt
  1545.             if (r.adr) {
  1546.               int bptr=0;
  1547.               char BIGSTK line[1024];
  1548.               char BIGSTK buff[8192];
  1549.               char BIGSTK infobuff[8192];
  1550.               int record=0;
  1551.               line[0]='\0'; buff[0]='\0'; infobuff[0]='\0';
  1552.               //
  1553. #if DEBUG_ROBOTS
  1554.               printf("robots.txt dump:\n%s\n",r.adr);
  1555. #endif
  1556.               do {
  1557.                 char* comm;
  1558.                 int llen;
  1559.                 bptr+=binput(r.adr+bptr, line, sizeof(line) - 2);
  1560.                 /* strip comment */
  1561.                 comm=strchr(line, '#');
  1562.                 if (comm != NULL) {
  1563.                   *comm = '\0';
  1564.                 }
  1565.                 /* strip spaces */
  1566.                 llen=strlen(line);
  1567.                 while(llen > 0 && is_realspace(line[llen - 1])) {
  1568.                   line[llen - 1] = '\0';
  1569.                   llen--;
  1570.                 }
  1571.                 if (strfield(line,"user-agent:")) {
  1572.                   char* a;
  1573.                   a=line+11;
  1574.                   while(is_realspace(*a)) a++;    // sauter espace(s)
  1575.                   if ( *a == '*') {
  1576.                     if (record != 2)
  1577.                       record=1;    // c pour nous
  1578.                   } else if (strfield(a,"httrack") || strfield(a,"winhttrack") || strfield(a,"webhttrack")) {
  1579.                     buff[0]='\0';      // re-enregistrer
  1580.                     infobuff[0]='\0';
  1581.                     record=2;          // locked
  1582. #if DEBUG_ROBOTS
  1583.                     printf("explicit disallow for httrack\n");
  1584. #endif
  1585.                   }
  1586.                   else record=0;
  1587.                 } else if (record) {
  1588.                   if (strfield(line,"disallow:")) {
  1589.                     char* a=line+9;
  1590.                     while(is_realspace(*a))
  1591.                       a++;    // sauter espace(s)
  1592.                     if (strnotempty(a)) {
  1593.                       if (strcmp(a,"/") != 0 || opt.robots >= 3) {      /* ignoring disallow: / */
  1594.                         if ( (strlen(buff) + strlen(a) + 8) < sizeof(buff)) {
  1595.                           strcatbuff(buff,a);
  1596.                           strcatbuff(buff,"\n");
  1597.                           if ( (strlen(infobuff) + strlen(a) + 8) < sizeof(infobuff)) {
  1598.                             if (strnotempty(infobuff)) strcatbuff(infobuff,", ");
  1599.                             strcatbuff(infobuff,a);
  1600.                           }
  1601.                         }
  1602.                       } else {
  1603.                         if (opt.errlog!=NULL) {
  1604.                           fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: %s robots.txt rules are too restrictive, ignoring /"LF,urladr);
  1605.                           test_flush;
  1606.                         }
  1607.                       }
  1608.                     }
  1609.                   }
  1610.                 }
  1611.               } while( (bptr<r.size) && (strlen(buff) < (sizeof(buff) - 32) ) );
  1612.               if (strnotempty(buff)) {
  1613.                 checkrobots_set(&robots,urladr,buff);
  1614.                 if (opt.log!=NULL) {
  1615.                   if (opt.log != opt.errlog) {
  1616.                     fspc(opt.log,"info"); fprintf(opt.log,"Note: robots.txt forbidden links for %s are: %s"LF,urladr,infobuff);
  1617.                     test_flush;
  1618.                   } 
  1619.                 }
  1620.                 if (opt.errlog!=NULL) {
  1621.                   fspc(opt.errlog,"info"); fprintf(opt.errlog,"Note: due to %s remote robots.txt rules, links begining with these path will be forbidden: %s (see in the options to disable this)"LF,urladr,infobuff);
  1622.                   test_flush;
  1623.                 }
  1624.               }
  1625.             }
  1626.           }
  1627.         } else if (r.is_write) {    // dΘja sauvΘ sur disque
  1628.           /*
  1629.           if (!ishttperror(r.statuscode))
  1630.             HTS_STAT.stat_files++;
  1631.           HTS_STAT.stat_bytes+=r.size;
  1632.           */
  1633.           //printf("ok......\n");
  1634.         } else {
  1635.           // Si on doit sauver une page HTML sans la scanner, cela signifie que le niveau de
  1636.           // rΘcursion nous en empΩche
  1637.           // Dans ce cas on met un fichier indiquant ce fait
  1638.           // Si par la suite on doit retraiter ce fichier avec un niveau de rΘcursion plus
  1639.           // fort, on supprimera le readme, et on scannera le fichier html!
  1640.           // note: sautΘ si store_errpage (cαd si page d'erreur, non α scanner!)
  1641.           if ( (is_hypertext_mime(r.contenttype, urlfil)) && (!store_errpage) && (r.size>0)) {  // c'est du html!!
  1642.             char BIGSTK tempo[HTS_URLMAXSIZE*2];
  1643.             FILE* fp;
  1644.             tempo[0]='\0';
  1645.             strcpybuff(tempo,savename);
  1646.             strcatbuff(tempo,".readme");
  1647.             
  1648. #if HTS_DOSNAME
  1649.             // remplacer / par des slash arriΦre
  1650.             {
  1651.               int i=0;
  1652.               while(tempo[i]) {
  1653.                 if (tempo[i]=='/')
  1654.                   tempo[i]='\\';
  1655.                 i++;
  1656.               } 
  1657.             } 
  1658.             // a partir d'ici le slash devient antislash
  1659. #endif
  1660.             
  1661.             if ((fp=fopen(tempo,"wb"))!=NULL) {
  1662.               fprintf(fp,"Info-file generated by HTTrack Website Copier "HTTRACK_VERSION"%s"CRLF""CRLF, WHAT_is_available);
  1663.               fprintf(fp,"The file %s has not been scanned by HTS"CRLF,savename);
  1664.               fprintf(fp,"Some links contained in it may be unreachable locally."CRLF);
  1665.               fprintf(fp,"If you want to get these files, you have to set an upper recurse level, ");
  1666.               fprintf(fp,"and to rescan the URL."CRLF);
  1667.               fclose(fp);
  1668. #if HTS_WIN==0
  1669.               chmod(tempo,HTS_ACCESS_FILE);      
  1670. #endif
  1671.               usercommand(&opt,0,NULL,fconv(tempo),"","");
  1672.             }
  1673.             
  1674.             
  1675.             if ( (opt.debug>0) && (opt.errlog!=NULL) ) {
  1676.               fspc(opt.errlog,"warning"); fprintf(opt.errlog,"Warning: store %s without scan: %s"LF,r.contenttype,savename);
  1677.               test_flush;
  1678.             }
  1679.           } else {
  1680.             if ((opt.getmode & 2)!=0) {    // ok autorisΘ
  1681.               if ( (opt.debug>1) && (opt.log!=NULL) ) {
  1682.                 fspc(opt.log,"debug"); fprintf(opt.log,"Store %s: %s"LF,r.contenttype,savename);
  1683.                 test_flush;
  1684.               }
  1685.             } else {    // lien non autorisΘ! (ex: cgi-bin en html)
  1686.               if ((opt.debug>1) && (opt.log!=NULL)) {
  1687.                 fspc(opt.log,"debug"); fprintf(opt.log,"non-html file ignored after upload at %s : %s"LF,urladr,urlfil);
  1688.                 test_flush;
  1689.               } 
  1690.               if (r.adr) {
  1691.                 freet(r.adr); r.adr=NULL;
  1692.               }
  1693.             }
  1694.           }
  1695.           
  1696.           //printf("extern=%s\n",r.contenttype);
  1697.  
  1698.           // ATTENTION C'EST ICI QU'ON SAUVE LE FICHIER!!          
  1699.           if (r.adr) {
  1700.             if (filesave(&opt,r.adr,(int)r.size,savename,urladr,urlfil)!=0) {
  1701.               int fcheck;
  1702.               if ((fcheck=check_fatal_io_errno())) {
  1703.                 exit_xh=-1;   /* fatal error */
  1704.               }
  1705.               if (opt.errlog) {   
  1706.                 fspc(opt.errlog,"error"); fprintf(opt.errlog,"Unable to save file %s : %s"LF, savename, strerror(errno));
  1707.                 if (fcheck) {
  1708.                   fspc(opt.errlog,"error");
  1709.                   fprintf(opt.errlog,"* * Fatal write error, giving up"LF);
  1710.                 }
  1711.                 test_flush;
  1712.               }
  1713.             } else {
  1714.               /*
  1715.               if (!ishttperror(r.statuscode))
  1716.                 HTS_STAT.stat_files++;
  1717.               HTS_STAT.stat_bytes+=r.size;
  1718.               */
  1719.             }
  1720.           }
  1721.           
  1722.         }
  1723.   
  1724.  
  1725.         /* Parsing of other media types (java, ram..) */
  1726.         /*
  1727.         if (strfield2(r.contenttype,"audio/x-pn-realaudio")) {
  1728.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1729.             fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): parsing %s"LF,savename); test_flush;
  1730.           }
  1731.           if (fexist(savename)) {   // ok, existe bien!
  1732.             FILE* fp=fopen(savename,"r+b");
  1733.             if (fp) {
  1734.               if (!fseek(fp,0,SEEK_SET)) {
  1735.                 char BIGSTK line[HTS_URLMAXSIZE*2];
  1736.                 linput(fp,line,HTS_URLMAXSIZE);
  1737.                 if (strnotempty(line)) {
  1738.                   if ((opt.debug>1) && (opt.log!=NULL)) {
  1739.                     fspc(opt.log,"debug"); fprintf(opt.log,"(Real Media): detected %s"LF,line); test_flush;
  1740.                   }
  1741.                 }
  1742.               }
  1743.               fclose(fp);
  1744.             }
  1745.           }
  1746.         } else */
  1747.  
  1748.  
  1749.         /* External modules */
  1750.         if (opt.parsejava && fexist(savename)) {
  1751.           char BIGSTK buff_err_msg[1024];
  1752.           htsmoduleStruct BIGSTK str;
  1753.           buff_err_msg[0] = '\0';
  1754.           memset(&str, 0, sizeof(str));
  1755.           /* */
  1756.           str.err_msg = buff_err_msg;
  1757.           str.filename = savename;
  1758.           str.mime = r.contenttype;
  1759.           str.url_host = urladr;
  1760.           str.url_file = urlfil;
  1761.           str.size = (int) r.size;
  1762.           /* */
  1763.           str.addLink = htsAddLink;
  1764.           /* */
  1765.           str.liens = liens;
  1766.           str.opt = &opt;
  1767.           str.back = back;
  1768.           str.back_max = back_max;
  1769.           str.cache = &cache;
  1770.           str.hashptr = hashptr;
  1771.           str.numero_passe = numero_passe;
  1772.           str.add_tab_alloc = add_tab_alloc;
  1773.           /* */
  1774.           str.lien_tot_ = &lien_tot;
  1775.           str.ptr_ = &ptr;
  1776.           str.lien_size_ = &lien_size;
  1777.           str.lien_buffer_ = &lien_buffer;
  1778.           /* Parse if recognized */
  1779.           switch(hts_parse_externals(&str)) {
  1780.           case 1:
  1781.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1782.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): parsed successfully %s"LF,savename); test_flush;
  1783.             }
  1784.             break;
  1785.           case 0:
  1786.             if ((opt.debug>1) && (opt.log!=NULL)) {
  1787.               fspc(opt.log,"debug"); fprintf(opt.log,"(External module): couldn't parse successfully %s : %s"LF,savename, str.err_msg); test_flush;
  1788.             }
  1789.             break;
  1790.           }
  1791.         }
  1792.              
  1793.         
  1794.       }  // text/html ou autre
  1795.       
  1796.  
  1797.       /* Post-processing */
  1798.       if (fexist(savename)) {
  1799.         usercommand(&opt, 0, NULL, savename, urladr, urlfil);
  1800.       }
  1801.  
  1802.  
  1803.     }  // if !error
  1804.     
  1805.  
  1806. jump_if_done:
  1807.     // libΘrer les liens
  1808.     if (r.adr) { 
  1809.       freet(r.adr); 
  1810.       r.adr=NULL; 
  1811.     }   // libΘrer la mΘmoire!
  1812.     
  1813.     // prochain lien
  1814.     ptr++;
  1815.     
  1816.     // faut-il sauter le(s) lien(s) suivant(s)? (fichiers images α passer aprΦs les html)
  1817.     if (opt.getmode & 4) {    // sauver les non html aprΦs
  1818.       // sauter les fichiers selon la passe
  1819.       if (!numero_passe) {
  1820.         while((ptr<lien_tot)?(   liens[ptr]->pass2):0) ptr++;
  1821.       } else {
  1822.         while((ptr<lien_tot)?( ! liens[ptr]->pass2):0) ptr++;
  1823.       }
  1824.       if (ptr>=lien_tot) {     // fin de boucle
  1825.         if (!numero_passe) { // premiΦre boucle
  1826.           if ((opt.debug>1) && (opt.log!=NULL)) {
  1827.             fprintf(opt.log,LF"Now getting non-html files..."LF);
  1828.             test_flush;
  1829.           }
  1830.           numero_passe=1;   // seconde boucle
  1831.           ptr=0;
  1832.           // prochain pass2
  1833.           while((ptr<lien_tot)?(!liens[ptr]->pass2):0) ptr++;
  1834.           
  1835.           //printf("first link==%d\n");
  1836.           
  1837.         }
  1838.       }  
  1839.     }
  1840.  
  1841.     // copy abort state if necessary from outside
  1842.     if (!exit_xh && opt.state.exit_xh) {
  1843.       exit_xh=opt.state.exit_xh;
  1844.     }
  1845.     // a-t-on dΘpassΘ le quota?
  1846.     if (!back_checkmirror(&opt)) {
  1847.       ptr=lien_tot;
  1848.     } else if (exit_xh) {  // sortir
  1849.       if (opt.errlog) {
  1850.         fspc(opt.errlog,"info"); 
  1851.         if (exit_xh==1) {
  1852.           fprintf(opt.errlog,"Exit requested by shell or user"LF);
  1853.         } else {
  1854.           fprintf(opt.errlog,"Exit requested by engine"LF);
  1855.         }
  1856.         test_flush;
  1857.       } 
  1858.       ptr=lien_tot;
  1859.     }
  1860.   } while(ptr<lien_tot);
  1861.   //
  1862.   //
  1863.   //
  1864.   
  1865.   /*
  1866.   Ensure the index is being closed
  1867.   */
  1868.   HT_INDEX_END;
  1869.   
  1870.   /* 
  1871.     updating-a-remotely-deteted-website hack
  1872.     no much data transfered, no data saved
  1873.     <no files successfulyl saved>
  1874.     we assume that something was bad (no connection)
  1875.     just backup old cache and restore everything
  1876.   */
  1877.   if (
  1878.     (HTS_STAT.stat_files <= 0) 
  1879.     && 
  1880.     (HTS_STAT.HTS_TOTAL_RECV < 32768)    /* should be fine */
  1881.     ) {
  1882.     if (opt.errlog) {
  1883.       fspc(opt.errlog,"info"); fprintf(opt.errlog,"No data seems to have been transfered during this session! : restoring previous one!"LF);
  1884.       test_flush;
  1885.     } 
  1886.     XH_uninit;
  1887.     if ( (fexist(fconcat(opt.path_log,"hts-cache/old.dat"))) && (fexist(fconcat(opt.path_log,"hts-cache/old.ndx"))) ) {
  1888.       remove(fconcat(opt.path_log,"hts-cache/new.dat"));
  1889.       remove(fconcat(opt.path_log,"hts-cache/new.ndx"));
  1890.       remove(fconcat(opt.path_log,"hts-cache/new.lst"));
  1891.       remove(fconcat(opt.path_log,"hts-cache/new.txt"));
  1892.       rename(fconcat(opt.path_log,"hts-cache/old.dat"),fconcat(opt.path_log,"hts-cache/new.dat"));
  1893.       rename(fconcat(opt.path_log,"hts-cache/old.ndx"),fconcat(opt.path_log,"hts-cache/new.ndx"));
  1894.       rename(fconcat(opt.path_log,"hts-cache/old.lst"),fconcat(opt.path_log,"hts-cache/new.lst"));
  1895.       rename(fconcat(opt.path_log,"hts-cache/old.txt"),fconcat(opt.path_log,"hts-cache/new.txt"));
  1896.     }
  1897.     exit_xh=2;        /* interrupted (no connection detected) */
  1898.     return 1;
  1899.   }
  1900.  
  1901.   // info text  
  1902.   if (cache.txt) {
  1903.     fclose(cache.txt); cache.txt=NULL;
  1904.   }
  1905.  
  1906.   // purger!
  1907.   if (cache.lst) {
  1908.     fclose(cache.lst); cache.lst=NULL;
  1909.     if (opt.delete_old) {
  1910.       FILE *old_lst,*new_lst;
  1911.       //
  1912. #if HTS_ANALYSTE
  1913.       _hts_in_html_parsing=3;
  1914. #endif
  1915.       //
  1916.       old_lst=fopen(fconcat(opt.path_log,"hts-cache/old.lst"),"rb");
  1917.       if (old_lst) {
  1918.         LLint sz=fsize(fconcat(opt.path_log,"hts-cache/new.lst"));
  1919.         new_lst=fopen(fconcat(opt.path_log,"hts-cache/new.lst"),"rb");
  1920.         if ((new_lst) && (sz>0)) {
  1921.           char* adr=(char*) malloct((INTsys)sz);
  1922.           if (adr) {
  1923.             if (fread(adr,1,(INTsys)sz,new_lst) == sz) {
  1924.               char line[1100];
  1925.               int purge=0;
  1926.               while(!feof(old_lst)) {
  1927.                 linput(old_lst,line,1000);
  1928.                 if (!strstr(adr,line)) {    // fichier non trouvΘ dans le nouveau?
  1929.                   char BIGSTK file[HTS_URLMAXSIZE*2];
  1930.                   strcpybuff(file,opt.path_html);
  1931.                   strcatbuff(file,line+1);
  1932.                   file[strlen(file)-1]='\0';
  1933.                   if (fexist(file)) {       // toujours sur disque: virer
  1934.                     if (opt.log) {
  1935.                       fspc(opt.log,"info"); fprintf(opt.log,"Purging %s"LF,file);
  1936.                     }
  1937.                     remove(file); purge=1;
  1938.                   }
  1939.                 }
  1940.               }
  1941.               {
  1942.                 fseek(old_lst,0,SEEK_SET);
  1943.                 while(!feof(old_lst)) {
  1944.                   linput(old_lst,line,1000);
  1945.                   while(strnotempty(line) && (line[strlen(line)-1]!='/') && (line[strlen(line)-1]!='\\')) {
  1946.                     line[strlen(line)-1]='\0';
  1947.                   }
  1948.                   if (strnotempty(line))
  1949.                     line[strlen(line)-1]='\0';
  1950.                   if (strnotempty(line))
  1951.                     if (!strstr(adr,line)) {    // non trouvΘ?
  1952.                       char BIGSTK file[HTS_URLMAXSIZE*2];
  1953.                       strcpybuff(file,opt.path_html);
  1954.                       strcatbuff(file,line+1);
  1955.                       while ((strnotempty(file)) && (rmdir(file)==0)) {    // ok, ΘliminΘ (existait)
  1956.                         purge=1;
  1957.                         if (opt.log) {
  1958.                           fspc(opt.log,"info"); fprintf(opt.log,"Purging directory %s/"LF,file);
  1959.                           while(strnotempty(file) && (file[strlen(file)-1]!='/') && (file[strlen(file)-1]!='\\')) {
  1960.                             file[strlen(file)-1]='\0';
  1961.                           }
  1962.                           if (strnotempty(file))
  1963.                             file[strlen(file)-1]='\0';
  1964.                         }
  1965.                       }
  1966.                     }
  1967.                 }
  1968.               }
  1969.               //
  1970.               if (!purge) {
  1971.                 if (opt.log) {
  1972.                   fprintf(opt.log,"No files purged"LF);
  1973.                 }
  1974.               }
  1975.             }
  1976.             freet(adr);
  1977.           }
  1978.           fclose(new_lst);
  1979.         }
  1980.         fclose(old_lst);
  1981.       }
  1982.       //
  1983. #if HTS_ANALYSTE
  1984.       _hts_in_html_parsing=0;
  1985. #endif
  1986.     }
  1987.   }
  1988.   // fin purge!
  1989.  
  1990.   // Indexation
  1991.   if (opt.kindex)
  1992.     index_finish(opt.path_html,opt.kindex);
  1993.  
  1994.   // afficher rΘsumΘ dans log
  1995.   if (opt.log!=NULL) {
  1996.     char BIGSTK finalInfo[8192];
  1997.     int error   = fspc(NULL,"error");
  1998.     int warning = fspc(NULL,"warning");
  1999.     int info    = fspc(NULL,"info");
  2000.     char BIGSTK htstime[256];
  2001.     char BIGSTK infoupdated[256];
  2002.     // int n=(int) (stat_loaded/(time_local()-HTS_STAT.stat_timestart));
  2003.     LLint n=(LLint) (HTS_STAT.HTS_TOTAL_RECV/(max(1,time_local()-HTS_STAT.stat_timestart)));
  2004.     
  2005.     sec2str(htstime,time_local()-HTS_STAT.stat_timestart);
  2006.     //sprintf(finalInfo + strlen(finalInfo),LF"HTS-mirror complete in %s : %d links scanned, %d files written (%d bytes overall) [%d bytes received at %d bytes/sec]"LF,htstime,lien_tot-1,HTS_STAT.stat_files,stat_bytes,stat_loaded,n);
  2007.     infoupdated[0] = '\0';
  2008.     if (opt.is_update) {
  2009.       if (HTS_STAT.stat_updated_files > 0) {
  2010.         sprintf(infoupdated, ", %d files updated", (int)HTS_STAT.stat_updated_files);
  2011.       } else {
  2012.         sprintf(infoupdated, ", no files updated");
  2013.       }
  2014.     }
  2015.     finalInfo[0] = '\0';
  2016.     sprintf(finalInfo + strlen(finalInfo),
  2017.       "HTTrack Website Copier/"HTTRACK_VERSION" mirror complete in %s : "
  2018.       "%d links scanned, %d files written ("LLintP" bytes overall)%s "
  2019.       "["LLintP" bytes received at "LLintP" bytes/sec]",
  2020.       htstime,
  2021.       (int)lien_tot-1,
  2022.       (int)HTS_STAT.stat_files,
  2023.       (LLint)HTS_STAT.stat_bytes,
  2024.       infoupdated,
  2025.       (LLint)HTS_STAT.HTS_TOTAL_RECV,
  2026.       (LLint)n
  2027.       );
  2028.  
  2029.     if (HTS_STAT.total_packed > 0 && HTS_STAT.total_unpacked > 0) {
  2030.       int packed_ratio=(int)((LLint)(HTS_STAT.total_packed*100)/HTS_STAT.total_unpacked);
  2031.       sprintf(finalInfo + strlen(finalInfo),", "LLintP" bytes transfered using HTTP compression in %d files, ratio %d%%",(LLint)HTS_STAT.total_unpacked,HTS_STAT.total_packedfiles,(int)packed_ratio);
  2032.     }
  2033.     if (!opt.nokeepalive && HTS_STAT.stat_sockid > 0 && HTS_STAT.stat_nrequests > HTS_STAT.stat_sockid) {
  2034.       int rq = (HTS_STAT.stat_nrequests * 10) / HTS_STAT.stat_sockid;
  2035.       sprintf(finalInfo + strlen(finalInfo),", %d.%d requests per connection", rq/10, rq%10);
  2036.     }
  2037.     sprintf(finalInfo + strlen(finalInfo),LF);
  2038.     if (error)
  2039.       sprintf(finalInfo + strlen(finalInfo),"(%d errors, %d warnings, %d messages)"LF,error,warning,info);
  2040.     else
  2041.       sprintf(finalInfo + strlen(finalInfo),"(No errors, %d warnings, %d messages)"LF,warning,info);
  2042.  
  2043.     // Log
  2044.     fprintf(opt.log,LF"%s", finalInfo);
  2045.  
  2046.     // Close ZIP
  2047.     if (cache.zipOutput) {
  2048.       zipClose(cache.zipOutput, finalInfo);
  2049.       cache.zipOutput = NULL;
  2050.     }
  2051.     
  2052.     test_flush;
  2053.   }
  2054. #if DEBUG_HASH
  2055.   // noter les collisions
  2056.   {
  2057.     int i;
  2058.     int empty1=0,empty2=0,empty3=0;
  2059.     for(i=0;i<HTS_HASH_SIZE;i++) {
  2060.       if (hash.hash[0][i] == -1)
  2061.         empty1++;
  2062.       if (hash.hash[1][i] == -1)
  2063.         empty2++;
  2064.       if (hash.hash[2][i] == -1)
  2065.         empty3++;
  2066.     }
  2067.     printf("\n");
  2068.     printf("Debug info: Hash-table report\n");
  2069.     printf("Number of files entered:   %d\n",hashnumber);
  2070.     printf("Table size:                %d\n",HTS_HASH_SIZE);
  2071.     printf("\n");
  2072.     printf("Longest chain sav:              %d, empty: %d\n",longest_hash[0],empty1);
  2073.     printf("Longest chain adr,fil:          %d, empty: %d\n",longest_hash[1],empty2);
  2074.     printf("Longest chain former_adr/fil:   %d, empty: %d\n",longest_hash[2],empty3);
  2075.     printf("\n");
  2076.   }
  2077. #endif    
  2078.   // fin afficher rΘsumΘ dans log
  2079.  
  2080.   // ending
  2081.   usercommand(&opt,0,NULL,NULL,NULL,NULL);
  2082.  
  2083.   // dΘsallocation mΘmoire & buffers
  2084.   XH_uninit;
  2085.  
  2086.   return 1;    // OK
  2087. }
  2088. // version 2 pour le reste
  2089. // flusher si on doit lire peu α peu le fichier
  2090. #undef test_flush
  2091. #define test_flush if (opt->flush) { fflush(opt->log); fflush(opt->errlog); }
  2092.  
  2093.  
  2094. // Estimate transfer rate
  2095. // a little bit complex, but not too much
  2096. /*
  2097.   .. : idle
  2098.   ^  : event
  2099.  
  2100.   ----|----|----|----|----|----|----|----|---->
  2101.    1    2    3    4    5    6    7    8    9   time (seconds)
  2102.   ----|----|----|----|----|----|----|----|---->
  2103.   ^........^.........^.........^.........^.... timer 0
  2104.   ----^.........^.........^.........^......... timer 1
  2105.            0    1    0    1    0    1    0     timer N sets its statistics
  2106.       *         *         *         *          timer 0 resync timer 1
  2107.  
  2108.   Therefore, each seconds, we resync the transfer rate with 2-seconds
  2109.  
  2110. */
  2111. int engine_stats(void) {
  2112. #if 0
  2113.   static FILE* debug_fp=NULL; /* ok */
  2114.   if (!debug_fp)
  2115.     debug_fp=fopen("esstat.txt","wb");
  2116. #endif
  2117.   HTS_STAT.stat_nsocket=HTS_STAT.stat_errors=HTS_STAT.nbk==0;
  2118.   HTS_STAT.nb=0;
  2119.   if (HTS_STAT.HTS_TOTAL_RECV>2048) {
  2120.     TStamp cdif=mtime_local();
  2121.     int i;
  2122.  
  2123.     for(i=0;i<2;i++) {
  2124.       if ( (cdif - HTS_STAT.istat_timestart[i]) >= 2000) {
  2125.         TStamp dif;
  2126. #if 0
  2127. fprintf(debug_fp,"set timer %d\n",i); fflush(debug_fp);
  2128. #endif
  2129.         dif=cdif - HTS_STAT.istat_timestart[i];
  2130.         if ((TStamp)(dif/1000)>0) {
  2131.           LLint byt=(HTS_STAT.HTS_TOTAL_RECV - HTS_STAT.istat_bytes[i]);
  2132.           HTS_STAT.rate=(LLint)((TStamp) ((TStamp)byt/(dif/1000)));
  2133.           HTS_STAT.istat_idlasttimer=i;      // this timer recently sets the stats
  2134.           //
  2135.           HTS_STAT.istat_bytes[i]=HTS_STAT.HTS_TOTAL_RECV;
  2136.           HTS_STAT.istat_timestart[i]=cdif;
  2137.         }
  2138.         return 1;       /* refreshed */
  2139.       }
  2140.     }
  2141.  
  2142.     // resynchronization between timer 0 (master) and 1 (slave)
  2143.     // timer #0 resync timer #1 when reaching 1 second limit
  2144.     if (HTS_STAT.istat_reference01 != HTS_STAT.istat_timestart[0]) {
  2145.       if ( (cdif - HTS_STAT.istat_timestart[0]) >= 1000) {
  2146. #if 0
  2147. fprintf(debug_fp,"resync timer 1\n"); fflush(debug_fp);
  2148. #endif
  2149.         HTS_STAT.istat_bytes[1]=HTS_STAT.HTS_TOTAL_RECV;
  2150.         HTS_STAT.istat_timestart[1]=cdif;
  2151.         HTS_STAT.istat_reference01=HTS_STAT.istat_timestart[0];
  2152.       }
  2153.     }
  2154.  
  2155.   }
  2156.   return 0;
  2157. }
  2158.  
  2159.  
  2160. #define _FILTERS     (*opt->filters.filters)
  2161. #define _FILTERS_PTR (opt->filters.filptr)
  2162. #define _ROBOTS      ((robots_wizard*)opt->robotsptr)
  2163.  
  2164. // bannir host (trop lent etc)
  2165. void host_ban(httrackp* opt,lien_url** liens,int ptr,int lien_tot,lien_back* back,int back_max,char* host) {
  2166.   //int l;
  2167.   int i;
  2168.  
  2169.   if (host[0]=='!')
  2170.     return;    // erreur.. dΘja cancellΘ.. bizarre.. devrait pas arriver
  2171.  
  2172.   /* sanity check */
  2173.   if (*_FILTERS_PTR + 1 >= opt->maxfilter) {
  2174.     opt->maxfilter += HTS_FILTERSINC;
  2175.     if (filters_init(&_FILTERS, opt->maxfilter, HTS_FILTERSINC) == 0) {
  2176.       printf("PANIC! : Too many filters : >%d [%d]\n",*_FILTERS_PTR,__LINE__);
  2177.       if (opt->errlog) {
  2178.         fprintf(opt->errlog,LF"Too many filters, giving up..(>%d)"LF,*_FILTERS_PTR);
  2179.         fprintf(opt->errlog,"To avoid that: use #F option for more filters (example: -#F5000)"LF);
  2180.         fflush(opt->errlog);
  2181.       }
  2182.       assertf("too many filters - giving up" == NULL);
  2183.     }
  2184.   }
  2185.  
  2186.   // interdire host
  2187.   assertf((*_FILTERS_PTR) < opt->maxfilter);
  2188.   if (*_FILTERS_PTR < opt->maxfilter) {
  2189.     strcpybuff(_FILTERS[*_FILTERS_PTR],"-");
  2190.     strcatbuff(_FILTERS[*_FILTERS_PTR],host);
  2191.     strcatbuff(_FILTERS[*_FILTERS_PTR],"/*");     // host/ * interdit
  2192.     (*_FILTERS_PTR)++; 
  2193.   }
  2194.   
  2195.   // oups
  2196.   if (strlen(host)<=1) {    // euhh?? longueur <= 1
  2197.     if (strcmp(host,"file://")) {
  2198.       //## if (host[0]!=lOCAL_CHAR) {  // pas local
  2199.       if (opt->log!=NULL) {
  2200.         fprintf(opt->log,"PANIC! HostCancel detected memory leaks [char %d]"LF,host[0]); test_flush;
  2201.       }          
  2202.       return;  // purΘe
  2203.     }
  2204.   }
  2205.   
  2206.   // couper connexion
  2207.   for(i=0;i<back_max;i++) {
  2208.     if (back[i].status>=0)    // rΘception OU prΩt
  2209.       if (strfield2(back[i].url_adr,host)) {
  2210. #if HTS_DEBUG_CLOSESOCK
  2211.         DEBUG_W("host control: deletehttp\n");
  2212. #endif
  2213.         back[i].status=0;  // terminΘ
  2214.         if (back[i].r.soc!=INVALID_SOCKET) deletehttp(&back[i].r);
  2215.         back[i].r.soc=INVALID_SOCKET;
  2216.         back[i].r.statuscode=-2;    // timeout (peu importe si c'est un traffic jam)
  2217.         strcpybuff(back[i].r.msg,"Link Cancelled by host control");
  2218.         
  2219.         if ((opt->debug>1) && (opt->log!=NULL)) {
  2220.           fprintf(opt->log,"Shutdown: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2221.         }          
  2222.       }
  2223.   }
  2224.   
  2225.   // effacer liens
  2226.   //l=strlen(host);
  2227.   for(i=0;i<lien_tot;i++) {
  2228.     //if (liens[i]->adr_len==l) {    // mΩme taille de chaεne
  2229.     // Calcul de taille sΘcurisΘe
  2230.     if (liens[i]) {
  2231.       if (liens[i]->adr) {
  2232.         int l = 0;
  2233.         while((liens[i]->adr[l]) && (l<1020)) l++;
  2234.         if ((l > 0) && (l<1020)) {   // sΘcuritΘ
  2235.           if (strfield2(jump_identification(liens[i]->adr),host)) {    // host
  2236.             if ((opt->debug>1) && (opt->log!=NULL)) {
  2237.               fprintf(opt->log,"Cancel: %s%s"LF,liens[i]->adr,liens[i]->fil); test_flush;
  2238.             }
  2239.             strcpybuff(liens[i]->adr,"!");    // cancel (invalide hash)
  2240. #if HTS_HASH
  2241. #else
  2242.             liens[i]->sav_len=-1;         // taille invalide
  2243. #endif
  2244.             // on efface pas le hash, because si on rencontre le lien, reverif sav..
  2245.           }
  2246.         } else {
  2247.           if (opt->log!=NULL) {
  2248.             char dmp[1040];
  2249.             dmp[0]='\0';
  2250.             strncatbuff(dmp,liens[i]->adr,1024);
  2251.             fprintf(opt->log,"WARNING! HostCancel detected memory leaks [len %d at %d]"LF,l,i); test_flush;
  2252.             fprintf(opt->log,"dump 1024 bytes (address %p): "LF"%s"LF,liens[i]->adr,dmp); test_flush;
  2253.           }          
  2254.         }
  2255.       } else {
  2256.         if (opt->log!=NULL) {
  2257.           fprintf(opt->log,"WARNING! HostCancel detected memory leaks [adr at %d]"LF,i); test_flush;
  2258.         }  
  2259.       }
  2260.     } else {
  2261.       if (opt->log!=NULL) {
  2262.         fprintf(opt->log,"WARNING! HostCancel detected memory leaks [null at %d]"LF,i); test_flush;
  2263.       }  
  2264.     }
  2265.     //}
  2266.   }
  2267. }
  2268.  
  2269.  
  2270. #if 0
  2271. /* Init structure */
  2272. /* 1 : init */
  2273. /* -1 : off */
  2274. /* 0 : query */
  2275. /* 2 : LOCK */
  2276. /* -2 : UNLOCK */
  2277. void* structcheck_init(int init) {
  2278.   int structcheck_size = 1024;
  2279.   inthash structcheck_hash=NULL;
  2280.   /* */
  2281.   static PTHREAD_LOCK_TYPE structcheck_init_mutex;
  2282.   static int structcheck_init_mutex_init=0;
  2283.  
  2284.   if (init == 1 || init == -1) {
  2285.     if (init) {
  2286.       if (structcheck_hash)
  2287.         inthash_delete(&structcheck_hash);
  2288.       structcheck_hash=NULL;
  2289.     }
  2290.     if (init != -1) {
  2291.       if (structcheck_init_mutex_init == 0) {
  2292.         htsSetLock(&structcheck_init_mutex, -999);
  2293.         structcheck_init_mutex_init=1;
  2294.       }
  2295.       if (structcheck_hash==NULL) {
  2296.         structcheck_hash=inthash_new(structcheck_size);  // dΘsallouΘ xh_xx
  2297.       }
  2298.     }
  2299.   }
  2300.  
  2301.   /* Lock / Unlock */
  2302.   if (init == 2) {  // Lock
  2303.     htsSetLock(&structcheck_init_mutex, 1);
  2304.   } else if (init == -2) {  // Unlock
  2305.     htsSetLock(&structcheck_init_mutex, 0);
  2306.   }
  2307.   return structcheck_hash;
  2308. }
  2309. #endif
  2310.  
  2311. int filters_init(char*** ptrfilters, int maxfilter, int filterinc) {
  2312.   char** filters = *ptrfilters;
  2313.   int filter_max=maximum(maxfilter, 128);
  2314.   if (filters == NULL) {
  2315.     filters=(char**) malloct( sizeof(char*) * (filter_max+2) );
  2316.     memset(filters, 0, sizeof(char*) * (filter_max+2));  // filters[0] == 0
  2317.   } else {
  2318.     filters=(char**) realloct(filters, sizeof(char*) * (filter_max+2) );
  2319.   }
  2320.   if (filters) {
  2321.     if (filters[0] == NULL) {
  2322.       filters[0]=(char*) malloct( sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2323.       memset(filters[0], 0, sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2324.     } else {
  2325.       filters[0]=(char*) realloct(filters[0], sizeof(char) * (filter_max+2) * (HTS_URLMAXSIZE*2) );
  2326.     }
  2327.     if (filters[0] == NULL) {
  2328.       freet(filters);
  2329.       filters = NULL;
  2330.     }
  2331.   }
  2332.   if (filters != NULL) {
  2333.     int i;
  2334.     int from;
  2335.     if (filterinc == 0)
  2336.       from = 0;
  2337.     else
  2338.       from = filter_max - filterinc;
  2339.     for(i=0 ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2340.       filters[i]=filters[0]+i*(HTS_URLMAXSIZE*2);
  2341.     }
  2342.     for(i=from ; i<=filter_max ; i++) {    // PLUS UN (sΘcuritΘ)
  2343.       filters[i][0]='\0';    // clear
  2344.     }
  2345.   }
  2346.   *ptrfilters = filters;
  2347.   return (filters != NULL) ? filter_max : 0;
  2348. }
  2349.  
  2350. // vΘrifier prΘsence de l'arbo
  2351. HTSEXT_API int structcheck(char* s) {
  2352.   // vΘrifier la prΘsence des dossier(s)
  2353.   char *a=s;
  2354.   char BIGSTK nom[HTS_URLMAXSIZE*2];
  2355.   char *b;
  2356.   //inthash structcheck_hash=NULL;
  2357.   if (strnotempty(s)==0) return 0;
  2358.   if (strlen(s)>HTS_URLMAXSIZE) return 0;
  2359.  
  2360.   // Get buffer address
  2361.   /*
  2362.   structcheck_hash = (inthash)structcheck_init(0);
  2363.   if (structcheck_hash == NULL) {
  2364.     return -1;
  2365.   }
  2366.   */
  2367.  
  2368.   b=nom;
  2369.   do {    
  2370.     if (*a) *b++=*a++;
  2371.     while((*a!='/') && (*a!='\0')) *b++=*a++;
  2372.     *b='\0';    // pas de ++ pour boucler
  2373.     if (*a=='/') {    // toujours dossier
  2374.       if (strnotempty(nom)) {         
  2375.         //if (inthash_write(structcheck_hash, nom, 1)) {    // non encore crΘΘ                       
  2376. #if HTS_WIN
  2377.         if (mkdir(fconv(nom))!=0)
  2378. #else    
  2379.           if (mkdir(fconv(nom),HTS_ACCESS_FOLDER)!=0)
  2380. #endif
  2381.           {
  2382. #if HTS_REMOVE_ANNOYING_INDEX
  2383.             // might be a filename with same name than this folder
  2384.             // then, remove it to allow folder creation
  2385.             // it happends when servers gives a folder index while
  2386.             // requesting / page
  2387.             // -> if the file can be opened (not a folder) then rename it
  2388.             if (fexist(fconv(nom))) {
  2389.               rename(fconv(nom),fconcat(fconv(nom),".txt"));
  2390.             }
  2391.             // if it fails, that's too bad
  2392. #if HTS_WIN
  2393.             mkdir(fconv(nom));
  2394. #else    
  2395.             mkdir(fconv(nom),HTS_ACCESS_FOLDER);
  2396. #endif
  2397. #endif
  2398.             // Si existe dΘja renvoie une erreur.. tant pis
  2399.           }
  2400. #if HTS_WIN==0
  2401.           /*chmod(fconv(nom),HTS_ACCESS_FOLDER);*/
  2402. #endif
  2403.           //}
  2404.       }
  2405.       *b++=*a++;    // slash
  2406.     } 
  2407.   } while(*a);
  2408.   return 0;
  2409. }
  2410.  
  2411.  
  2412. // sauver un fichier
  2413. int filesave(httrackp* opt,char* adr,int len,char* s,char* url_adr,char* url_fil) {
  2414.   FILE* fp;
  2415.   // Θcrire le fichier
  2416.   if ((fp=filecreate(s))!=NULL) {
  2417.     int nl=0;
  2418.     if (len>0) {
  2419.       nl=(int) fwrite(adr,1,(INTsys)len,fp);
  2420.     }
  2421.     fclose(fp);
  2422.     //xxusercommand(opt,0,NULL,fconv(s),url_adr,url_fil);
  2423.     if (nl!=len)  // erreur
  2424.       return -1;
  2425.   } else
  2426.     return -1;
  2427.   
  2428.   return 0;
  2429. }
  2430.  
  2431. /* We should stop */
  2432. int check_fatal_io_errno(void) {
  2433.   switch(errno) {
  2434. #ifdef EMFILE
  2435.   case EMFILE: /* Too many open files */
  2436. #endif
  2437. #ifdef ENOSPC
  2438.   case ENOSPC: /* No space left on device */
  2439. #endif
  2440. #ifdef EROFS
  2441.   case EROFS:  /* Read-only file system */
  2442. #endif
  2443.     return 1;
  2444.     break;
  2445.   }
  2446.   return 0;
  2447. }
  2448.  
  2449.  
  2450. // ouvrir un fichier (avec chemin Un*x)
  2451. FILE* filecreate(char* s) {
  2452.   char BIGSTK fname[HTS_URLMAXSIZE*2];
  2453.   FILE* fp;
  2454.   fname[0]='\0';
  2455.  
  2456.   // noter lst
  2457.   filenote(s,NULL);
  2458.   
  2459.   // if (*s=='/') strcpybuff(fname,s+1); else strcpybuff(fname,s);    // pas de / (root!!) // ** SIIIIIII!!! α cause de -O <path>
  2460.   strcpybuff(fname,s);
  2461.  
  2462. #if HTS_DOSNAME
  2463.   // remplacer / par des slash arriΦre
  2464.   {
  2465.     int i=0;
  2466.     while(fname[i]) {
  2467.       if (fname[i]=='/')
  2468.         fname[i]='\\';
  2469.       i++;
  2470.     } 
  2471.   } 
  2472.   // a partir d'ici le slash devient antislash
  2473. #endif
  2474.   
  2475.   // ouvrir
  2476.   fp=fopen(fname,"wb");
  2477.   if (fp == NULL) {
  2478.     // construire le chemin si besoin est
  2479.     (void)structcheck(s);
  2480.     fp=fopen(fname,"wb");
  2481.   }
  2482.   
  2483. #if HTS_WIN==0
  2484.   if (fp!=NULL) chmod(fname,HTS_ACCESS_FILE);
  2485. #endif
  2486.  
  2487.   return fp;
  2488. }
  2489.  
  2490. // create an empty file
  2491. int filecreateempty(char* filename) {
  2492.   FILE* fp;
  2493.   fp=filecreate(filename);      // filenote & co
  2494.   if (fp) {
  2495.     fclose(fp);
  2496.     return 1;
  2497.   } else
  2498.     return 0; 
  2499. }
  2500.  
  2501. // noter fichier
  2502. typedef struct {
  2503.   FILE* lst;
  2504.   char path[HTS_URLMAXSIZE*2];
  2505. } filenote_strc;
  2506. int filenote(char* s,filecreate_params* params) {
  2507.   filenote_strc* strc;
  2508.   NOSTATIC_RESERVE(strc, filenote_strc, 1);
  2509.   
  2510.   // gestion du fichier liste liste
  2511.   if (params) {
  2512.     //filecreate_params* p = (filecreate_params*) params;
  2513.     strcpybuff(strc->path,params->path);
  2514.     strc->lst=params->lst;
  2515.     return 0;
  2516.   } else if (strc->lst) {
  2517.     char BIGSTK savelst[HTS_URLMAXSIZE*2];
  2518.     strcpybuff(savelst,fslash(s));
  2519.     // couper chemin?
  2520.     if (strnotempty(strc->path)) {
  2521.       if (strncmp(fslash(strc->path),savelst,strlen(strc->path))==0) {  // couper
  2522.         strcpybuff(savelst,s+strlen(strc->path));
  2523.       }
  2524.     }
  2525.     fprintf(strc->lst,"[%s]"LF,savelst);
  2526.     fflush(strc->lst);
  2527.   }
  2528.   return 1;
  2529. }
  2530.  
  2531. // executer commande utilisateur
  2532. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil);
  2533. typedef struct {
  2534.   int exe;
  2535.   char cmd[2048];
  2536. } usercommand_strc;
  2537. HTS_INLINE void usercommand(httrackp* opt,int _exe,char* _cmd,char* file,char* adr,char* fil) {
  2538.   usercommand_strc* strc;
  2539.   NOSTATIC_RESERVE(strc, usercommand_strc, 1);
  2540.   
  2541.   /* Callback */
  2542.   if (_exe) {
  2543.     strcpybuff(strc->cmd,_cmd);
  2544.     if (strnotempty(strc->cmd))
  2545.       strc->exe=_exe;
  2546.     else
  2547.       strc->exe=0;
  2548.   }
  2549.  
  2550.   /* post-processing */
  2551.   postprocess_file(opt, file, adr, fil);
  2552.  
  2553. #if HTS_ANALYSTE
  2554.   if (hts_htmlcheck_filesave != NULL)
  2555.   if (file != NULL && strnotempty(file))
  2556.     hts_htmlcheck_filesave(file);
  2557. #endif
  2558.  
  2559.   if (strc->exe) {
  2560.     if (file != NULL && strnotempty(file)) {
  2561.       if (strnotempty(strc->cmd)) {
  2562.         usercommand_exe(strc->cmd,file);
  2563.       }
  2564.     }
  2565.   }
  2566. }
  2567. void usercommand_exe(char* cmd,char* file) {
  2568.   char BIGSTK temp[8192];
  2569.   char c[2]="";
  2570.   int i;
  2571.   temp[0]='\0';
  2572.   //
  2573.   for(i=0;i<(int) strlen(cmd);i++) {
  2574.     if ((cmd[i]=='$') && (cmd[i+1]=='0')) {
  2575.       strcatbuff(temp,file);
  2576.       i++;
  2577.     } else {
  2578.       c[0]=cmd[i]; c[1]='\0';
  2579.       strcatbuff(temp,c);
  2580.     }
  2581.   }
  2582.   system(temp);
  2583. }
  2584.  
  2585.  
  2586. static void postprocess_file(httrackp* opt,char* save, char* adr, char* fil) {
  2587.   int first = 0;
  2588.   /* MIME-html archive to build */
  2589.   if (opt != NULL && opt->mimehtml) {
  2590.     if (adr != NULL && strcmp(adr, "primary") == 0) {
  2591.       adr = NULL;
  2592.     }
  2593.     if (save != NULL && opt != NULL && adr != NULL && adr[0] && strnotempty(save) && fexist(save)) {
  2594.       char* rsc_save = save;
  2595.       char* rsc_fil = strrchr(fil, '/');
  2596.       int n;
  2597.       if (rsc_fil == NULL)
  2598.         rsc_fil = fil;
  2599.       if (strncmp(fslash(save), fslash(opt->path_html), (n = (int)strlen(opt->path_html))) == 0) {
  2600.         rsc_save += n;
  2601.       }
  2602.  
  2603.       if (!opt->state.mimehtml_created) {
  2604.         first = 1;
  2605.         opt->state.mimefp = fopen(fconcat(opt->path_html,"index.mht"), "wb");
  2606.         if (opt->state.mimefp != NULL) {
  2607.           char BIGSTK rndtmp[1024], currtime[256];
  2608.           srand(time(NULL));
  2609.           time_gmt_rfc822(currtime);
  2610.           sprintf(rndtmp, "%d_%d", (int)time(NULL), (int) rand());
  2611.           sprintf(opt->state.mimemid, "----=_MIMEPart_%s_=----", rndtmp);
  2612.           fprintf(opt->state.mimefp, "From: HTTrack Website Copier <nobody@localhost>\r\n"
  2613.             "Subject: Local mirror\r\n"
  2614.             "Date: %s\r\n"
  2615.             "Message-ID: <httrack_%s@localhost>\r\n"
  2616.             "Content-Type: multipart/related;\r\n"
  2617.             "\tboundary=\"%s\";\r\n"
  2618.             "\ttype=\"text/html\"\r\n"
  2619.             "MIME-Version: 1.0\r\n"
  2620.             "\r\nThis message is a RFC MIME-compliant multipart message.\r\n"
  2621.             "\r\n"
  2622.             , currtime, rndtmp, opt->state.mimemid);
  2623.           opt->state.mimehtml_created = 1;
  2624.         } else {
  2625.           opt->state.mimehtml_created = -1;
  2626.           if ( opt->errlog != NULL ) {
  2627.             fspc(opt->errlog,"error"); fprintf(opt->log,"unable to create index.mht"LF);
  2628.           }
  2629.         }
  2630.       }
  2631.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2632.         FILE* fp = fopen(save, "rb");
  2633.         if (fp != NULL) {
  2634.           char buff[60*100 + 2];
  2635.           char mimebuff[256];
  2636.           char BIGSTK cid[HTS_URLMAXSIZE*3];
  2637.           int len;
  2638.           int isHtml = ( ishtml(save) == 1 );
  2639.           mimebuff[0] = '\0';
  2640.  
  2641.           /* CID */
  2642.           strcpybuff(cid, adr);
  2643.           strcatbuff(cid, fil);
  2644.           escape_in_url(cid);
  2645.           { char* a = cid; while((a = strchr(a, '%'))) { *a = 'X'; a++; } }
  2646.           
  2647.           guess_httptype(mimebuff, save);
  2648.           fprintf(opt->state.mimefp, "--%s\r\n", opt->state.mimemid);
  2649.           /*if (first)
  2650.           fprintf(opt->state.mimefp, "Content-disposition: inline\r\n");
  2651.           else*/
  2652.           fprintf(opt->state.mimefp, "Content-disposition: attachment; filename=\"%s\"\r\n", rsc_save);
  2653.           fprintf(opt->state.mimefp, 
  2654.             "Content-Type: %s\r\n"
  2655.             "Content-Transfer-Encoding: %s\r\n"
  2656.             /*"Content-Location: http://localhost/%s\r\n"*/
  2657.             "Content-ID: <%s>\r\n"
  2658.             "\r\n"
  2659.             , mimebuff
  2660.             , isHtml ? "8bit" : "base64"
  2661.             /*, rsc_save*/
  2662.             , cid);
  2663.           while((len = fread(buff, 1, sizeof(buff) - 2, fp)) > 0) {
  2664.             buff[len] = '\0';
  2665.             if (!isHtml) {
  2666.               char base64buff[60*100*2];
  2667.               code64((unsigned char*)buff, len, (unsigned char*)base64buff, 1);
  2668.               fprintf(opt->state.mimefp, "%s", base64buff);
  2669.             } else {
  2670.               fprintf(opt->state.mimefp, "%s", buff);
  2671.             }
  2672.           }
  2673.           fclose(fp);
  2674.           fprintf(opt->state.mimefp, "\r\n\r\n");
  2675.         }
  2676.       }
  2677.     } else if (save == NULL) {
  2678.       if (opt->state.mimehtml_created == 1 && opt->state.mimefp != NULL) {
  2679.         fprintf(opt->state.mimefp, 
  2680.           "--%s--\r\n", opt->state.mimemid);
  2681.         fclose(opt->state.mimefp);
  2682.         opt->state.mimefp = NULL;
  2683.       }
  2684.     }
  2685.   }
  2686. }
  2687.  
  2688. // Θcrire n espaces dans fp
  2689. typedef struct {
  2690.   int error;
  2691.   int warning;
  2692.   int info;
  2693. } fspc_strc;
  2694. HTS_INLINE int fspc(FILE* fp,char* type) {
  2695.   fspc_strc* strc;
  2696.   NOSTATIC_RESERVE(strc, fspc_strc, 1); // log..
  2697.  
  2698.   //
  2699.   if (fp) {
  2700.     char s[256];
  2701.     time_t tt;
  2702.     struct tm* A;
  2703.     tt=time(NULL);
  2704.     A=localtime(&tt);
  2705.     if (A == NULL) {
  2706.       int localtime_returned_null=0;
  2707.       assert(localtime_returned_null);
  2708.     }
  2709.     strftime(s,250,"%H:%M:%S",A);
  2710.     if (strnotempty(type))
  2711.       fprintf(fp,"%s\t%c%s: \t",s,hichar(*type),type+1);
  2712.     else
  2713.       fprintf(fp,"%s\t \t",s);
  2714.     if (strcmp(type,"warning")==0)
  2715.       strc->warning++;
  2716.     else if (strcmp(type,"error")==0)
  2717.       strc->error++;
  2718.     else if (strcmp(type,"info")==0)
  2719.       strc->info++;
  2720.   } 
  2721.   else if (!type)
  2722.     strc->error=strc->warning=strc->info=0;     // reset
  2723.   else if (strcmp(type,"warning")==0)
  2724.     return strc->warning;
  2725.   else if (strcmp(type,"error")==0)
  2726.     return strc->error;
  2727.   else if (strcmp(type,"info")==0)
  2728.     return strc->info;
  2729.   return 0;
  2730. }
  2731.  
  2732.  
  2733. // vΘrifier taux de transfert
  2734. #if 0
  2735. void check_rate(TStamp stat_timestart,int maxrate) {
  2736.   // vΘrifier taux de transfert (pas trop grand?)
  2737.   /*
  2738.   if (maxrate>0) {
  2739.     int r = (int) (HTS_STAT.HTS_TOTAL_RECV/(time_local()-stat_timestart));    // taux actuel de transfert
  2740.     HTS_STAT.HTS_TOTAL_RECV_STATE=0;
  2741.     if (r>maxrate) {    // taux>taux autorisΘ
  2742.       int taux = (int) (((TStamp) (r - maxrate) * 100) / (TStamp) maxrate);
  2743.       if (taux<15)
  2744.         HTS_STAT.HTS_TOTAL_RECV_STATE=1;   // ralentir un peu (<15% dΘpassement)
  2745.       else if (taux<50)
  2746.         HTS_STAT.HTS_TOTAL_RECV_STATE=2;   // beaucoup (<50% dΘpassement)
  2747.       else
  2748.         HTS_STAT.HTS_TOTAL_RECV_STATE=3;   // ΘnormΘment (>50% dΘpassement)
  2749.     }
  2750.   }
  2751.   */
  2752. }
  2753. #endif
  2754.  
  2755. // ---
  2756. // sous routines liΘes au moteur et au backing
  2757.  
  2758. // supplemental links ready (done) after ptr
  2759. int backlinks_done(lien_url** liens,int lien_tot,int ptr) {
  2760.   int n=0;
  2761.   int i;
  2762.   //Links done and stored in cache
  2763.   for(i=ptr+1;i<lien_tot;i++) {
  2764.     if (liens[i]) {
  2765.       if (liens[i]->pass2 == -1) {
  2766.         n++;
  2767.       }
  2768.     }
  2769.   }
  2770.   return n;
  2771. }
  2772.  
  2773. // remplir backing si moins de max_bytes en mΘmoire
  2774. HTS_INLINE int back_fillmax(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2775.   if (!opt->state.stop) {
  2776.     if (back_incache(back,back_max)<opt->maxcache) {  // pas trop en mΘmoire?
  2777.       return back_fill(back,back_max,opt,cache,liens,ptr,numero_passe,lien_tot);
  2778.     }
  2779.   }
  2780.   return -1;                /* plus de place */
  2781. }
  2782.  
  2783. int back_pluggable_sockets_strict(lien_back* back, int back_max, httrackp* opt) {
  2784.   int n = opt->maxsoc - back_nsoc(back, back_max);
  2785.  
  2786.   // connect limiter
  2787.   if (n > 0 && opt->maxconn > 0 && HTS_STAT.last_connect > 0) {
  2788.     TStamp opTime = HTS_STAT.last_request ? HTS_STAT.last_request : HTS_STAT.last_connect;
  2789.     TStamp cTime = mtime_local();
  2790.     TStamp lap = ( cTime - opTime );
  2791.     TStamp minLap = (TStamp) ( 1000.0 / opt->maxconn );
  2792.     if (lap < minLap) {
  2793.       n = 0;
  2794.     } else {
  2795.       int nMax = (int) ( lap / minLap );
  2796.       n = min(n, nMax);
  2797.     }
  2798.   }
  2799.  
  2800.   return n;
  2801. }
  2802.  
  2803. int back_pluggable_sockets(lien_back* back, int back_max, httrackp* opt) {
  2804.   int n;
  2805.  
  2806.   // ajouter autant de socket qu'on peut ajouter
  2807.   n=back_pluggable_sockets_strict(back, back_max, opt);
  2808.  
  2809.   // vΘrifier qu'il restera assez de place pour les tests ensuite (en thΘorie, 1 entrΘe libre restante suffirait)
  2810.   n=min( n, back_available(back,back_max) - 8 );
  2811.  
  2812.   // no space left on backing stack - do not back anymore
  2813.   if (back_stack_available(back,back_max) <= 2)
  2814.     n=0;
  2815.  
  2816.   return n;
  2817. }
  2818.  
  2819. // remplir backing
  2820. int back_fill(lien_back* back,int back_max,httrackp* opt,cache_back* cache,lien_url** liens,int ptr,int numero_passe,int lien_tot) {
  2821.   int n = back_pluggable_sockets(back, back_max, opt);
  2822.   if (n>0) {
  2823.     int p;
  2824.  
  2825.     if (ptr<cache->ptr_last) {      /* restart (2 scans: first html, then non html) */
  2826.       cache->ptr_ant=0;
  2827.     }
  2828.  
  2829.     p=ptr+1;
  2830.     /* on a dΘja parcouru */
  2831.     if (p<cache->ptr_ant)
  2832.       p=cache->ptr_ant;
  2833.     while( (p<lien_tot) && (n>0) && back_checkmirror(opt)) {
  2834.     //while((p<lien_tot) && (n>0) && (p < ptr+opt->maxcache_anticipate)) {
  2835.       int ok=1;
  2836.       
  2837.       // on ne met pas le fichier en backing si il doit Ωtre traitΘ aprΦs
  2838.       if (liens[p]->pass2) {  // 2Φ passe
  2839.         if (numero_passe!=1)
  2840.           ok=0;
  2841.       } else {
  2842.         if (numero_passe!=0)
  2843.           ok=0;
  2844.       }
  2845.       
  2846.       // note: si un backing est fini, il reste en mΘmoire jusqu'α ce que
  2847.       // le ptr l'atteigne
  2848.       if (ok) {
  2849.         if (!back_exist(back,back_max,liens[p]->adr,liens[p]->fil,liens[p]->sav)) {
  2850.           if (back_add(back,back_max,opt,cache,liens[p]->adr,liens[p]->fil,liens[p]->sav,liens[liens[p]->precedent]->adr,liens[liens[p]->precedent]->fil,liens[p]->testmode,&liens[p]->pass2)==-1) {
  2851.             if ( (opt->debug>1) && (opt->errlog!=NULL) ) {
  2852.               fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: unable to add more links through back_add for back_fill"LF);
  2853.               test_flush;
  2854.             }                    
  2855. #if BDEBUG==1
  2856.             printf("error while adding\n");
  2857. #endif                  
  2858.             n=0;    // sortir
  2859.           } else {
  2860.             n--;
  2861. #if BDEBUG==1
  2862.             printf("backing: %s%s\n",liens[p]->adr,liens[p]->fil);          
  2863. #endif
  2864.           } 
  2865.         }
  2866.       }
  2867.       p++;
  2868.     }  // while
  2869.     /* sauver position derniΦre anticipation */
  2870.     cache->ptr_ant=p;
  2871.     cache->ptr_last=ptr;
  2872.   }
  2873.   return 0;
  2874. }
  2875. // ---
  2876.  
  2877.  
  2878.  
  2879.  
  2880.  
  2881.  
  2882.  
  2883.  
  2884.  
  2885.  
  2886.  
  2887.  
  2888.  
  2889.  
  2890.  
  2891.  
  2892.  
  2893.  
  2894. // routines de dΘtournement de SIGHUP & co (Unix)
  2895. //
  2896. httrackp* hts_declareoptbuffer(httrackp* optdecl) {
  2897.   static httrackp* opt=NULL; /* OK */
  2898.   if (optdecl) opt=optdecl;
  2899.   return opt;
  2900. }
  2901. //
  2902. void sig_finish( int code ) {       // finir et quitter
  2903.   signal(code,sig_term);  // quitter si encore
  2904.   exit_xh=1;
  2905.   fprintf(stderr,"\nExit requested to engine (signal %d)\n",code);
  2906. }
  2907. void sig_term( int code ) {       // quitter brutalement
  2908.   fprintf(stderr,"\nProgram terminated (signal %d)\n",code);
  2909.   exit(0);
  2910. }
  2911. #if HTS_WIN
  2912. void sig_ask( int code ) {        // demander
  2913.   char s[256];
  2914.   signal(code,sig_term);  // quitter si encore
  2915.   printf("\nQuit program/Interrupt/Cancel? (Q/I/C) ");
  2916.   fflush(stdout);
  2917.   scanf("%s",s);
  2918.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  2919.     exit(0);     // quitter
  2920.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  2921.     httrackp* opt=hts_declareoptbuffer(NULL);
  2922.     if (opt) {
  2923.       // ask for stop
  2924.       opt->state.stop=1;
  2925.     }
  2926.   }
  2927.   signal(code,sig_ask);  // remettre signal
  2928. }
  2929. #else
  2930. void sig_back( int code ) {       // ignorer et mettre en backing 
  2931.   signal(code,sig_ignore);
  2932.   sig_doback(0);
  2933. }
  2934. void sig_ask( int code ) {        // demander
  2935.   char s[256];
  2936.   signal(code,sig_term);  // quitter si encore
  2937.   printf("\nQuit program/Interrupt/Background/bLind background/Cancel? (Q/I/B/L/C) ");
  2938.   fflush(stdout);
  2939.   scanf("%s",s);
  2940.   if ( (s[0]=='y') || (s[0]=='Y') || (s[0]=='o') || (s[0]=='O') || (s[0]=='q') || (s[0]=='Q'))
  2941.     exit(0);     // quitter
  2942.   else if ( (s[0]=='b') || (s[0]=='B') || (s[0]=='a') || (s[0]=='A') )
  2943.     sig_doback(0);  // arriΦre plan
  2944.   else if ( (s[0]=='l') || (s[0]=='L') )
  2945.     sig_doback(1);  // arriΦre plan
  2946.   else if ( (s[0]=='i') || (s[0]=='I') ) {
  2947.     httrackp* opt=hts_declareoptbuffer(NULL);
  2948.     if (opt) {
  2949.       // ask for stop
  2950.       printf("finishing pending transfers.. please wait\n");
  2951.       opt->state.stop=1;
  2952.     }
  2953.     signal(code,sig_ask);  // remettre signal
  2954.   }
  2955.   else {
  2956.     printf("cancel..\n");
  2957.     signal(code,sig_ask);  // remettre signal
  2958.   }
  2959. }
  2960. void sig_ignore( int code ) {     // ignorer signal
  2961. }
  2962. void sig_brpipe( int code ) {     // treat if necessary
  2963.   signal(code, sig_brpipe);
  2964. }
  2965. void sig_doback(int blind) {       // mettre en backing 
  2966.   int out=-1;
  2967.   //
  2968.   printf("\nMoving into background to complete the mirror...\n"); fflush(stdout);
  2969.  
  2970.   {
  2971.     httrackp* opt=hts_declareoptbuffer(NULL);
  2972.     if (opt) {
  2973.       // suppress logging and asking lousy questions
  2974.       opt->quiet=1;
  2975.       opt->verbosedisplay=0;
  2976.     }
  2977.   }
  2978.  
  2979.   if (!blind)
  2980.     out = open("hts-nohup.out",O_CREAT|O_WRONLY,S_IRUSR|S_IWUSR);
  2981.   if (out == -1)
  2982.     out = open("/dev/null",O_WRONLY,S_IRUSR|S_IWUSR);
  2983.   close(0);
  2984.   close(1);
  2985.   dup(out);
  2986.   close(2);
  2987.   dup(out);
  2988.   //
  2989.   switch (fork()) {
  2990.   case 0: 
  2991.     break;
  2992.   case -1:
  2993.     fprintf(stderr,"Error: can not fork process\n");
  2994.     break;
  2995.   default:            // pere
  2996.     usleep(100000);   // pause 1/10s "A  microsecond  is  .000001s"
  2997.     _exit(0);
  2998.     break;  
  2999.   }
  3000. }
  3001. #endif
  3002. // fin routines de dΘtournement de SIGHUP & co
  3003.  
  3004. // Poll stdin.. si besoin
  3005. #if HTS_POLL
  3006. // lecture stdin des caractΦres disponibles
  3007. int read_stdin(char* s,int max) {
  3008.   int i=0;
  3009.   while((check_stdin()) && (i<(max-1)) )
  3010.     s[i++]=fgetc(stdin);
  3011.   s[i]='\0';
  3012.   return i;
  3013. }
  3014. #ifdef _WIN32
  3015. HTS_INLINE int check_stdin(void) {
  3016. #ifndef _WIN32_WCE
  3017.   return (_kbhit());
  3018. #else
  3019.   return 0;
  3020. #endif
  3021. }
  3022. #else
  3023. HTS_INLINE int check_flot(T_SOC s) {
  3024.   fd_set fds;
  3025.   struct timeval tv;
  3026.   FD_ZERO(&fds);
  3027.   FD_SET((T_SOC) s,&fds);
  3028.   tv.tv_sec=0;
  3029.   tv.tv_usec=0;
  3030.   select(s+1,&fds,NULL,NULL,&tv);
  3031.   return FD_ISSET(s,&fds);
  3032. }
  3033. HTS_INLINE int check_stdin(void) {
  3034.   fflush(stdout); fflush(stdin);
  3035.   if (check_flot(0))
  3036.     return 1;
  3037.   return 0;
  3038. }
  3039. #endif
  3040. #endif
  3041.  
  3042. HTS_INLINE int check_sockerror(T_SOC s) {
  3043.   fd_set fds;
  3044.   struct timeval tv;
  3045.   FD_ZERO(&fds);
  3046.   FD_SET((T_SOC) s,&fds);
  3047.   tv.tv_sec=0;
  3048.   tv.tv_usec=0;
  3049.   select(s+1,NULL,NULL,&fds,&tv);
  3050.   return FD_ISSET(s,&fds);
  3051. }
  3052.  
  3053. /* check incoming data */
  3054. HTS_INLINE int check_sockdata(T_SOC s) {
  3055.   fd_set fds;
  3056.   struct timeval tv;
  3057.   FD_ZERO(&fds);
  3058.   FD_SET((T_SOC) s,&fds);
  3059.   tv.tv_sec=0;
  3060.   tv.tv_usec=0;
  3061.   select(s+1,&fds,NULL,NULL,&tv);
  3062.   return FD_ISSET(s,&fds);
  3063. }
  3064.  
  3065. // Attente de touche
  3066. #if HTS_ANALYSTE
  3067. int ask_continue(void) {
  3068.   char* s;
  3069.   s=hts_htmlcheck_query2(HTbuff);
  3070.   if (s) {
  3071.     if (strnotempty(s)) {
  3072.       if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3073.         return 0;
  3074.     }
  3075.     return 1;
  3076.   }
  3077.   return 1;
  3078. }
  3079. #else
  3080. int ask_continue(void) {
  3081.   char s[12];
  3082.   s[0]='\0';
  3083.   printf("Press <Y><Enter> to confirm, <N><Enter> to abort\n");
  3084.   io_flush; linput(stdin,s,4);
  3085.   if (strnotempty(s)) {
  3086.     if ((strfield2(s,"N")) || (strfield2(s,"NO")) || (strfield2(s,"NON")))
  3087.       return 0;
  3088.   }
  3089.   return 1;
  3090. }
  3091. #endif
  3092.  
  3093. // nombre de digits dans un nombre
  3094. int nombre_digit(int n) {
  3095.   int i=1;
  3096.   while(n >= 10) { n/=10; i++; }
  3097.   return i;
  3098. }
  3099.  
  3100.  
  3101. // renvoi adresse de la fin du token dans p
  3102. // renvoi NULL si la chaine est un token unique
  3103. // (PATCHE Θgalement la chaine)
  3104. // ex: "test" "test2" renvoi adresse sur espace
  3105. // flag==1 si chaine comporte des echappements comme \"
  3106. char* next_token(char* p,int flag) {
  3107.   int detect=0;
  3108.   int quote=0;
  3109.   p--;
  3110.   do {
  3111.     p++;
  3112.     if (flag && (*p=='\\')) {   // sauter \x ou \"
  3113.       if (quote) {
  3114.         char c='\0';
  3115.         if (*(p+1)=='\\')
  3116.           c='\\';
  3117.         else if (*(p+1)=='"')
  3118.           c='"';
  3119.         if (c) {
  3120.           char BIGSTK tempo[8192];
  3121.           tempo[0]=c; tempo[1]='\0';
  3122.           strcatbuff(tempo,p+2);
  3123.           strcpybuff(p,tempo);
  3124.         }
  3125.       }
  3126.     }
  3127.     else if (*p==34) {  // guillemets (de fin)
  3128.       char BIGSTK tempo[8192];
  3129.       tempo[0]='\0';
  3130.       strcatbuff(tempo,p+1);
  3131.       strcpybuff(p,tempo);   /* wipe "" */
  3132.       p--;
  3133.       /* */
  3134.       quote=!quote;
  3135.     }
  3136.     else if (*p==32) {
  3137.       if (!quote)
  3138.         detect=1;
  3139.     }
  3140.     else if (*p=='\0') {
  3141.       p=NULL;
  3142.       detect=1;
  3143.     }
  3144.   } while(!detect);
  3145.   return p;
  3146. }
  3147.  
  3148. // routines annexes 
  3149. #if HTS_ANALYSTE
  3150. // canceller un fichier (noter comme cancellable)
  3151. // !!NOT THREAD SAFE!!
  3152. HTSEXT_API char* hts_cancel_file(char * s) {
  3153.   static char sav[HTS_URLMAXSIZE*2]="";
  3154.   if (s[0]!='\0')
  3155.   if (sav[0]=='\0')
  3156.     strcpybuff(sav,s);
  3157.   return sav;
  3158. }
  3159. HTSEXT_API void hts_cancel_test(void) {
  3160.   if (_hts_in_html_parsing==2)
  3161.     _hts_cancel=2;
  3162. }
  3163. HTSEXT_API void hts_cancel_parsing(void) {
  3164.   if (_hts_in_html_parsing)
  3165.    _hts_cancel=1;
  3166. }
  3167. #endif
  3168. //        for(_i=0;(_i<back_max) && (index<NStatsBuffer);_i++) {
  3169. //          i=(back_index+_i)%back_max;    // commencer par le "premier" (l'actuel)
  3170. //          if (back[i].status>=0) {     // signifie "lien actif"
  3171.  
  3172. #if 0
  3173. /*  
  3174. hts_add_file, add/get elements in the add chain for java parsing
  3175. if file_position >= 0
  3176.   push 'file/file_position'
  3177.   return 1 (return 0 if exists)
  3178. else
  3179.   pop file -> 'file'
  3180.   return 'file_position'
  3181. else if empty/error
  3182.   return -1;
  3183. */
  3184. typedef struct addfile_chain {
  3185.   char name[1024];
  3186.   int pos;
  3187.   struct addfile_chain* next;
  3188. } addfile_chain;
  3189. typedef addfile_chain* addfile_chain_ptr;
  3190. int opt->(char* file,int file_position) {
  3191.   addfile_chain** chain;
  3192.   NOSTATIC_RESERVE(chain, addfile_chain_ptr, 1);
  3193.  
  3194.   if (file_position>=0) {         /* copy file to the chain */
  3195.     struct addfile_chain** current;
  3196.     current=chain;                     /* start from */
  3197.     while(*current) {
  3198.       if (strcmp((*current)->name,file)==0)
  3199.         return 0;                       /* already exists */
  3200.       current=&( (*current)->next );    /* 'next' address */
  3201.     }
  3202.     *current=calloct(1,sizeof(addfile_chain));
  3203.     if (*current) {
  3204.       (*current)->next=NULL;
  3205.       (*current)->pos=-1;
  3206.       (*current)->name[0]='\0';
  3207.     }
  3208.     if (*current) {
  3209.       strcpybuff((*current)->name,file);
  3210.       (*current)->pos=file_position;
  3211.       return 1;
  3212.     } else {
  3213.       printf("PANIC! Too many Java files during parsing [1]\n");
  3214.       return -1;
  3215.     }
  3216.   } else {                      /* copy last element in file and delete it */
  3217.     if (file)
  3218.       file[0]='\0';
  3219.     if (*chain) {
  3220.       struct addfile_chain** current;
  3221.       int pos=-1;
  3222.       current=chain;                     /* start from */
  3223.       while( (*current)->next ) {
  3224.         current=&( (*current)->next );    /* 'next' address */
  3225.       }
  3226.       if (file)
  3227.         strcpybuff(file,(*current)->name);
  3228.       pos=(*current)->pos;
  3229.       freet(*current);
  3230.       *current=NULL;
  3231.       return pos;
  3232.     }
  3233.     return -1;                            /* no more elements */
  3234.   }
  3235.  
  3236.   return 0;
  3237. }
  3238. #endif
  3239.  
  3240. #if HTS_ANALYSTE
  3241. // en train de parser un fichier html? rΘponse: % effectuΘs
  3242. // flag>0 : refresh demandΘ
  3243. HTSEXT_API int hts_is_parsing(int flag) {
  3244.   if (_hts_in_html_parsing) {  // parsing?
  3245.     if (flag>=0) _hts_in_html_poll=1;  // faudrait un tit refresh
  3246.     return max(_hts_in_html_done,1); // % effectuΘs
  3247.   } else {
  3248.     return 0;                 // non
  3249.   }
  3250. }
  3251. HTSEXT_API int hts_is_testing(void) {            // 0 non 1 test 2 purge
  3252.   if (_hts_in_html_parsing==2)
  3253.     return 1;
  3254.   else if (_hts_in_html_parsing==3)
  3255.     return 2;
  3256.   else if (_hts_in_html_parsing==4)
  3257.     return 3;
  3258.   else if (_hts_in_html_parsing==5)   // scheduling
  3259.     return 4;
  3260.   else if (_hts_in_html_parsing==6)   // wait for slot
  3261.     return 5;
  3262.   return 0;
  3263. }
  3264. HTSEXT_API int hts_is_exiting(void) {
  3265.   return exit_xh;
  3266. }
  3267. // message d'erreur?
  3268. char* hts_errmsg(void) {
  3269.   return _hts_errmsg;
  3270. }
  3271. // mode pause transfer
  3272. HTSEXT_API int hts_setpause(int p) {
  3273.   if (p>=0) _hts_setpause=p;
  3274.   return _hts_setpause;
  3275. }
  3276. // ask for termination
  3277. HTSEXT_API int hts_request_stop(int force) {
  3278.   httrackp* opt=hts_declareoptbuffer(NULL);
  3279.   if (opt) {
  3280.     opt->state.stop=1;
  3281.   }
  3282.   return 0;
  3283. }
  3284. // rΘgler en cours de route les paramΦtres rΘglables..
  3285. // -1 : erreur
  3286. HTSEXT_API int hts_setopt(httrackp* set_opt) {
  3287.   if (set_opt) {
  3288.     httrackp* engine_opt=hts_declareoptbuffer(NULL);
  3289.     if (engine_opt) {
  3290.       //_hts_setopt=opt;
  3291.       copy_htsopt(set_opt,engine_opt);
  3292.     }
  3293.   }
  3294.   return 0;
  3295. }
  3296. // ajout d'URL
  3297. // -1 : erreur
  3298. HTSEXT_API int hts_addurl(char** url) {
  3299.   if (url) _hts_addurl=url;
  3300.   return (_hts_addurl!=NULL);
  3301. }
  3302. HTSEXT_API int hts_resetaddurl(void) {
  3303.   _hts_addurl=NULL;
  3304.   return (_hts_addurl!=NULL);
  3305. }
  3306. // copier nouveaux paramΦtres si besoin
  3307. HTSEXT_API int copy_htsopt(httrackp* from,httrackp* to) {
  3308.   if (from->maxsite > -1) 
  3309.     to->maxsite = from->maxsite;
  3310.   
  3311.   if (from->maxfile_nonhtml > -1) 
  3312.     to->maxfile_nonhtml = from->maxfile_nonhtml;
  3313.   
  3314.   if (from->maxfile_html > -1) 
  3315.     to->maxfile_html = from->maxfile_html;
  3316.   
  3317.   if (from->maxsoc > 0) 
  3318.     to->maxsoc = from->maxsoc;
  3319.   
  3320.   if (from->nearlink > -1) 
  3321.     to->nearlink = from->nearlink;
  3322.   
  3323.   if (from->timeout > -1) 
  3324.     to->timeout = from->timeout;
  3325.   
  3326.   if (from->rateout > -1)
  3327.     to->rateout = from->rateout;
  3328.   
  3329.   if (from->maxtime > -1) 
  3330.     to->maxtime = from->maxtime;
  3331.   
  3332.   if (from->maxrate > -1)
  3333.     to->maxrate = from->maxrate;
  3334.   
  3335.   if (from->maxconn > 0)
  3336.     to->maxconn = from->maxconn;
  3337.  
  3338.   if (strnotempty(from->user_agent)) 
  3339.     strcpybuff(to->user_agent , from->user_agent);
  3340.   
  3341.   if (from->retry > -1) 
  3342.     to->retry = from->retry;
  3343.   
  3344.   if (from->hostcontrol > -1) 
  3345.     to->hostcontrol = from->hostcontrol;
  3346.   
  3347.   if (from->errpage > -1) 
  3348.     to->errpage = from->errpage;
  3349.  
  3350.   if (from->parseall > -1) 
  3351.     to->parseall = from->parseall;
  3352.  
  3353.  
  3354.   // test all: bit 8 de travel
  3355.   if (from->travel > -1)  {
  3356.     if (from->travel & 256)
  3357.       to->travel|=256;
  3358.     else
  3359.       to->travel&=255;
  3360.   }
  3361.  
  3362.  
  3363.   return 0;
  3364. }
  3365.  
  3366. #endif
  3367. //
  3368.  
  3369. /* External modules callback */
  3370. int htsAddLink(htsmoduleStruct* str, char* link) {
  3371.   if (link != NULL && str != NULL && link[0] != '\0') {
  3372.     lien_url** liens = (lien_url**) str->liens;
  3373.     httrackp* opt = (httrackp*) str->opt;
  3374.     lien_back* back = (lien_back*) str->back;
  3375.     cache_back* cache = (cache_back*) str->cache;
  3376.     hash_struct* hashptr = (hash_struct*) str->hashptr;
  3377.     int back_max = str->back_max;
  3378.     int numero_passe = str->numero_passe;
  3379.     int add_tab_alloc = str->add_tab_alloc;
  3380.     /* */
  3381.     int lien_tot = * ( (int*) (str->lien_tot_) );
  3382.     int ptr = * ( (int*) (str->ptr_) );
  3383.     int lien_size = * ( (int*) (str->lien_size_) );
  3384.     char* lien_buffer = * ( (char**) (str->lien_buffer_) );
  3385.     /* */
  3386.     /* */
  3387.     char BIGSTK adr[HTS_URLMAXSIZE*2],
  3388.       fil[HTS_URLMAXSIZE*2],
  3389.       save[HTS_URLMAXSIZE*2];
  3390.     char BIGSTK codebase[HTS_URLMAXSIZE*2];
  3391.     /* */
  3392.     int pass_fix, prio_fix;
  3393.     /* */
  3394.     int forbidden_url = 1;
  3395.     
  3396.     codebase[0]='\0';
  3397.     
  3398.     if ((opt->debug>1) && (opt->log!=NULL)) {
  3399.       fspc(opt->log,"debug"); fprintf(opt->log,"(module): adding link : '%s'"LF, link); test_flush;
  3400.     }
  3401.     // recopie de "creer le lien"
  3402.     //    
  3403.  
  3404. #if HTS_ANALYSTE
  3405.   if (!hts_htmlcheck_linkdetected(link) || !hts_htmlcheck_linkdetected2(link, NULL)) {
  3406.     if (opt->errlog) {
  3407.       fspc(opt->errlog,"error"); fprintf(opt->errlog,"Link %s refused by external wrapper"LF, link);
  3408.       test_flush;
  3409.     }
  3410.     return 0;
  3411.   }
  3412. #endif
  3413.  
  3414.     // adr = c'est la mΩme
  3415.     // fil et save: save2 et fil2
  3416.     prio_fix=maximum(liens[ptr]->depth-1,0);
  3417.     pass_fix=max(liens[ptr]->pass2,numero_passe);
  3418.     if (liens[ptr]->cod) strcpybuff(codebase,liens[ptr]->cod);       // codebase valable pour tt les classes descendantes
  3419.     if (strnotempty(codebase)==0) {    // pas de codebase, construire
  3420.       char* a;
  3421.       if (str->relativeToHtmlLink == 0)
  3422.         strcpybuff(codebase,liens[ptr]->fil);
  3423.       else
  3424.         strcpybuff(codebase,liens[liens[ptr]->precedent]->fil);
  3425.       a=codebase+strlen(codebase)-1;
  3426.       while((*a) && (*a!='/') && ( a > codebase)) a--;
  3427.       if (*a=='/')
  3428.         *(a+1)='\0';    // couper
  3429.     } else {    // couper http:// Θventuel
  3430.       if (strfield(codebase,"http://")) {
  3431.         char BIGSTK tempo[HTS_URLMAXSIZE*2];
  3432.         char* a=codebase+7;
  3433.         a=strchr(a,'/');    // aprΦs host
  3434.         if (a) {  // ** msg erreur et vΘrifier?
  3435.           strcpybuff(tempo,a);
  3436.           strcpybuff(codebase,tempo);    // couper host
  3437.         } else {
  3438.           if (opt->errlog) {   
  3439.             fprintf(opt->errlog,"Unexpected strstr error in base %s"LF,codebase);
  3440.             test_flush;
  3441.           }
  3442.         }
  3443.       }
  3444.     }
  3445.     
  3446.     if (!((int) strlen(codebase)<HTS_URLMAXSIZE)) {    // trop long
  3447.       if (opt->errlog) {   
  3448.         fprintf(opt->errlog,"Codebase too long, parsing skipped (%s)"LF,codebase);
  3449.         test_flush;
  3450.       }
  3451.     }
  3452.     
  3453.     {
  3454.       char* lien = link;
  3455.       int dejafait=0;
  3456.       
  3457.       if (strnotempty(lien) && strlen(lien) < HTS_URLMAXSIZE) {
  3458.         
  3459.         // calculer les chemins et noms de sauvegarde
  3460.         if (ident_url_relatif(lien,urladr,codebase,adr,fil)>=0) { // reformage selon chemin
  3461.           int r;
  3462.           int set_prio_to = 0;
  3463.           int just_test_it = 0;
  3464.           forbidden_url = hts_acceptlink(opt, ptr, lien_tot, liens,
  3465.             adr,fil,
  3466.             NULL, NULL,
  3467.             &set_prio_to,
  3468.             &just_test_it);
  3469.           if ((opt->debug>1) && (opt->log!=NULL)) {
  3470.             fspc(opt->log,"debug"); fprintf(opt->log,"result for wizard external module link: %d"LF,forbidden_url);
  3471.             test_flush;
  3472.           }
  3473.  
  3474.           /* Link accepted */
  3475.           if (!forbidden_url) {
  3476.             char BIGSTK tempo[HTS_URLMAXSIZE*2];
  3477.             int a,b;
  3478.             tempo[0]='\0';
  3479.             a=opt->savename_type;
  3480.             b=opt->savename_83;
  3481.             opt->savename_type=0;
  3482.             opt->savename_83=0;
  3483.             // note: adr,fil peuvent Ωtre patchΘs
  3484.             r=url_savename(adr,fil,save,NULL,NULL,NULL,NULL,opt,liens,lien_tot,back,back_max,cache,hashptr,ptr,numero_passe);
  3485.             opt->savename_type=a;
  3486.             opt->savename_83=b;
  3487.             if (r != -1) {
  3488.               if (savename) {
  3489.                 if (lienrelatif(tempo,save,savename)==0) {
  3490.                   if ((opt->debug>1) && (opt->log!=NULL)) {
  3491.                     fspc(opt->log,"debug"); fprintf(opt->log,"(module): relative link at %s build with %s and %s: %s"LF,adr,save,savename,tempo);
  3492.                     test_flush;
  3493.                     if (str->localLink && str->localLinkSize > (int) strlen(tempo) + 1) {
  3494.                       strcpybuff(str->localLink, tempo);
  3495.                     }
  3496.                   }
  3497.                 }
  3498.               }
  3499.             }
  3500.           } else {
  3501.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3502.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): file not caught: %s"LF,lien); test_flush;
  3503.             }
  3504.             if (str->localLink && str->localLinkSize > (int) ( strlen(adr) + strlen(fil) +  8 ) ) {
  3505.               str->localLink[0] = '\0';
  3506.               if (!link_has_authority(adr))
  3507.                 strcpybuff(str->localLink,"http://");
  3508.               strcatbuff(str->localLink, adr);
  3509.               strcatbuff(str->localLink, fil);
  3510.             }
  3511.             r=-1;
  3512.           }
  3513.           //
  3514.           if (r != -1) {
  3515.             if ((opt->debug>1) && (opt->log!=NULL)) {
  3516.               fspc(opt->log,"debug"); fprintf(opt->log,"(module): %s%s -> %s (base %s)"LF,adr,fil,save,codebase); test_flush;
  3517.             }
  3518.             
  3519.             // modifiΘ par rapport α l'autre version (cf prio_fix notamment et save2)
  3520.             
  3521.             // vΘrifier que le lien n'a pas dΘja ΘtΘ notΘ
  3522.             // si c'est le cas, alors il faut s'assurer que la prioritΘ associΘe
  3523.             // au fichier est la plus grande des deux prioritΘs
  3524.             //
  3525.             // On part de la fin et on essaye de se presser (Θconomise temps machine)
  3526. #if HTS_HASH
  3527.             {
  3528.               int i=hash_read(hashptr,save,"",0,opt->urlhack);      // lecture type 0 (sav)
  3529.               if (i>=0) {
  3530.                 liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3531.                 dejafait=1;
  3532.               }
  3533.             }
  3534. #else
  3535.             {
  3536.               int l;
  3537.               int i;
  3538.               l=strlen(save);
  3539.               for(i=lien_tot-1;(i>=0) && (dejafait==0);i--) {
  3540.                 if (liens[i]->sav_len==l) {    // mΩme taille de chaεne
  3541.                   if (strcmp(liens[i]->sav,save)==0) {    // existe dΘja
  3542.                     liens[i]->depth=maximum(liens[i]->depth,prio_fix);
  3543.                     dejafait=1;
  3544.                   }
  3545.                 }
  3546.               }
  3547.             }
  3548. #endif
  3549.             
  3550.             
  3551.             if (!dejafait) {
  3552.               //
  3553.               // >>>> CREER LE LIEN JAVA <<<<
  3554.               
  3555.               // enregistrer fichier (MACRO)
  3556.               liens_record(adr,fil,save,"","",opt->urlhack);
  3557.               if (liens[lien_tot]==NULL) {  // erreur, pas de place rΘservΘe
  3558.                 printf("PANIC! : Not enough memory [%d]\n",__LINE__);
  3559.                 if (opt->errlog) { 
  3560.                   fprintf(opt->errlog,"Not enough memory, can not re-allocate %d bytes"LF,(int)((add_tab_alloc+1)*sizeof(lien_url)));
  3561.                   test_flush;
  3562.                 }
  3563.                 exit_xh=-1;    /* fatal error -> exit */
  3564.                 return 0;
  3565.               }  
  3566.               
  3567.               // mode test?                          
  3568.               liens[lien_tot]->testmode=0;          // pas mode test
  3569.               
  3570.               liens[lien_tot]->link_import=0;       // pas mode import
  3571.               
  3572.               // Θcrire autres paramΦtres de la structure-lien
  3573.               //if (meme_adresse)                                 
  3574.               liens[lien_tot]->premier=liens[ptr]->premier;
  3575.               //else    // sinon l'objet pΦre est le prΘcΘdent lui mΩme
  3576.               //  liens[lien_tot]->premier=ptr;
  3577.               
  3578.               liens[lien_tot]->precedent=ptr;
  3579.               // noter la prioritΘ
  3580.               if (!set_prio_to)
  3581.                 liens[lien_tot]->depth=prio_fix;
  3582.               else
  3583.                 liens[lien_tot]->depth=max(0,min(liens[ptr]->depth-1,set_prio_to-1));         // PRIORITE NULLE (catch page)
  3584.               liens[lien_tot]->pass2=max(pass_fix,numero_passe);
  3585.               liens[lien_tot]->retry=opt->retry;
  3586.               
  3587.               //strcpybuff(liens[lien_tot]->adr,adr);
  3588.               //strcpybuff(liens[lien_tot]->fil,fil);
  3589.               //strcpybuff(liens[lien_tot]->sav,save); 
  3590.               if ((opt->debug>1) && (opt->log!=NULL)) {
  3591.                 fspc(opt->log,"debug"); fprintf(opt->log,"(module): OK, NOTE: %s%s -> %s"LF,liens[lien_tot]->adr,liens[lien_tot]->fil,liens[lien_tot]->sav);
  3592.                 test_flush;
  3593.               }
  3594.               
  3595.               lien_tot++;  // UN LIEN DE PLUS
  3596.             }
  3597.           }
  3598.         }
  3599.       }
  3600.     }
  3601.     
  3602.     /* Apply changes */
  3603.     * ( (int*) (str->lien_tot_) ) = lien_tot;
  3604.     * ( (int*) (str->ptr_) ) = ptr;
  3605.     * ( (int*) (str->lien_size_) ) = lien_size;
  3606.     * ( (char**) (str->lien_buffer_) ) = lien_buffer;
  3607.     return (forbidden_url == 0);
  3608.   }
  3609.   return 0;
  3610. }
  3611.  
  3612.  
  3613.  
  3614.  
  3615.  
  3616. // message copyright interne
  3617. void voidf(void) {
  3618.   char* a;
  3619.   a=""CRLF""CRLF;
  3620.   a="+-----------------------------------------------+"CRLF;
  3621.   a="|HyperTextTRACKer, Offline Browser Utility      |"CRLF;
  3622.   a="|                      HTTrack Website Copier   |"CRLF;
  3623.   a="|Code:         Windows Interface Xavier Roche   |"CRLF;
  3624.   a="|                    HTS/HTTrack Xavier Roche   |"CRLF;
  3625.   a="|                .class Parser Yann Philippot   |"CRLF;
  3626.   a="|                                               |"CRLF;
  3627.   a="|Tested on:                 Windows95,98,NT,2K  |"CRLF;
  3628.   a="|                           Linux PC            |"CRLF;
  3629.   a="|                           Sun-Solaris 5.6     |"CRLF;
  3630.   a="|                           AIX 4               |"CRLF;
  3631.   a="|                                               |"CRLF;
  3632.   a="|Copyright (C) Xavier Roche and other           |"CRLF;
  3633.   a="|contributors                                   |"CRLF;
  3634.   a="|                                               |"CRLF;
  3635.   a="|Use this program at your own risks!            |"CRLF;    
  3636.   a="+-----------------------------------------------+"CRLF;
  3637.   a=""CRLF;
  3638. }
  3639.  
  3640.  
  3641. // HTTrack Website Copier Copyright (C) Xavier Roche and other contributors
  3642. //
  3643.  
  3644.